Behavior Driven Development for java - what framework to use? [closed]
Asked Answered
M

6

31

For the ongoing projects and for improving our development process we considered adopting TDD as development philosophy. While researching for best practices and how to "sell" the new approach to my colleagues/ developers I came across BDD and found it even more appropriate to what we would need and somehow to be next iteration of TDD. The problem is that up to now I tried only the tool developed by Dan North, JBehave and I cannot say that I am amazed.

The setup seems to me cumbersome and I couldn't find very appropriate documentation for it. On the other hand I tried also spock the groovy tool and up to now I kind of like it.

Q: are there any proper tools to be used for BDD?
Q: you would use instead spock and deal with the overhead of introducing another language?

Masseuse answered 16/4, 2013 at 11:42 Comment(3)
Hi Olimpiu, there are different flavors of BDD. Would it be valuable to include also non-technical stakeholders? If yes, what about using tools such as FitNesse or Concordion?Fearsome
@Fearsome - yes it would be highly appreciated to include also nontechnical stakeholders. Did you experiment in this direction?Masseuse
we are using Concordion in our team. non-technical business specialists are writing specifications with a free WYSIWYG html editor (microsoft.com/en-us/download/details.aspx?id=36179). the specifications are then instrumented by developers to create automated acceptance tests.Fearsome
G
45

Behavior Driven Development is just a technique that can be used without any tools. You can just write tests in BDD style - e.g. start test methods with should and introduce some separate feature with this method. When and then sections can be replaced with just comments, e.g.

@Test
public void should_do_something() {
    // given
    Something something = getSomething();

    // when
    something.doSomething();
    // then 
    assertSomething();

    // when
    something.doSomethingElse();
    // then 
    assertSomethingElse();
}

My opinion on the mentioned frameworks:

  • The problem with JBehave is that tests look like a complex spaceship. On the other hand it has pretty output for your specifications.

  • spock is really cool. Compact syntax, pretty output, a lot of features, written with the powerful groovy language, which means the possibility of usage in conjunction with geb. BUT it is groovy and it can be very important for someone.

  • scalatest (written with scala) and easyb (written with groovy) both have the same disadvantage as spock. The "... should ..." and "Given...Then" notation. Specifications are in .story files, and the step implementations are in Java classes. This approach work very well as a collaboration and communication tool to define the specs, but would usually be too much overhead for low-level coding.

I also think that the most successful BDD frameworks for Java are those that are not written in Java, since the Java language has no such flexibility for DSL (Domain Specific Language) creation that Groovy or Scala has.

Groundmass answered 17/4, 2013 at 9:56 Comment(1)
One persons opinion. I've had fantastic experiences with spock. No problem testing Java code, and groovy is incredibly easy for a Java programmer to pickup. You can start out writing regular Java and keep working, then gradually adopt the more terse style as you learn Groovy if desired. I was skeptical of Groovy, but spock is such a joy to use that it more than repays the minimal effort to learn a little bit of Groovy.Hydromancy
M
16

As the author of JGiven I have to disagree with sody that Java has not enough flexibility for DSL creation. In JGiven, BDD tests looks as follows:

@Test
public void users_can_login {
    given()
       .a_registered_user()
       .and().the_login_page_is_shown();

    when()
       .the_user_enters_correct_credentials()
       .and().the_login_button_is_pressed();

    then()
       .the_welcome_page_is_shown();
}

JGiven is used together with JUnit or TestNg and you write your tests in plain Java.

Meacham answered 9/8, 2014 at 17:48 Comment(5)
I have to disagree with You my friend. What you've presented has nothing to do with DSL. It's some kind of fluent API for Java (based on the static methods), but IMHO not much readable nor usable.Pontiff
Well, then please explain me the difference to a Groovy DSL. Btw, there is no static method here, these are all instance methods. In addition, the example I have shown is much more complex than the above example. However, whether it is useable or not should everybody decide for him or herself. JGiven gives you a tool that is much easier to use than Cucumber or JBehave and still provides scenario reports that are readable by business owners.Meacham
It's hard for me to call such API a DSL due to amount of parentheses and dots. In Java you cannot simply skip them. It's just my personal feeling.Pontiff
Maybe I write too much Java so that don't even see the parentheses anymore :-). However, as JGiven is a Java framework it can also be used in Groovy and Scala. In Groovy you can get at least get rid of the semicolons, in Scala you can also omit the parentheses.Meacham
Looks useful to me. I'm not interested in a DSL but very interested in more readable unit tests using BDD concepts. I'll never sell the entire business on DSL and pure BDD approach but I can at least do something about the lack of clarity in my unit tests.Crespo
G
14

Unless your product owner/qa/customer need to be able to read the tests, use Spock. It is very simple tool, but improves readability of tests. Thanks to it's powerful features you don't need Mockito, Hamcrest nor AssertJ. And it has superb parametrized tests. In fact, it is "just" a better JUnit - a general tool for automated execution of simple tasks, be it unit tests, integration tests or acceptance tests.

Fearing Groovy? Why? It is very similar to java. The more you learn it, the more expressive and shorter your code is. Your tests will be shorter and more readable. Groovy is gateway drug to the better side of JVM.

Don't like dynamic languages? Well, it is tests, and tests are run by CI server after every commit, right? If your code breaks, you will know it after few minutes. Don't have CI server or not running tests regularly? Then don't bother with choosing a test framework and go fix your process. Broken tests are useless and if you don't run the tests regularly, they will break soon.

Go with JBehave/Cucumber if you need it; Otherwise, use Spock.

Gorga answered 28/1, 2014 at 21:34 Comment(1)
Fearing Groovy? Why? - an ever growing list of polyglot solutions that make it more difficult to find talent.Crespo
T
4

Another alternative would be Spectrum - see https://github.com/greghaskins/spectrum

Spectrum supports the RSpec/Mocha syntax and in its next release will also support Gherkin syntax, along with JUnit rule integration (so it interoperates with Mockito, Spring etc via the @Rule and @ClassRule members).

Full disclosure - I'm a contributor to this OS project

Example:

@RunWith(Spectrum.class)
public class TestSomething {{
    Supplier<Something> freshTestObject = let(Something::new);

    describe("The component", () -> {
        it("is tested by specs", () -> {
            // the "let` above gives us a new instance of the object
            // in each spec
            freshTestObject.get().doSomething();

            // using your favourite assertion framework
            assertThat(something.get().getSomething()).isEqualTo(42);
        });
    });
}}

Spectrum outputs a hierarchical test result in your JUnit console. The strength of it is in mixing the Java implementation of the spec execution in with the spec definition - this can be more direct than frameworks that rely on feature files and glue code to parse them, especially if there's a need to pass results from one step of the test to another.

Spectrum aims to be polyglot, so should seem familiar to users of several existing frameworks.

Temple answered 26/1, 2017 at 11:1 Comment(0)
L
2

Give Ginkgo4j a go. It uses Java 8's lamda's to mirror the approach used by Ruby's RSpec and Go's Ginkgo.

This library allows you to build expressive, content-rich tests.

```

package com.github.paulcwarren.ginkgo4j.examples;

import static com.github.paulcwarren.ginkgo4j.Ginkgo4jDSL.*;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import org.junit.runner.RunWith;

import com.github.paulcwarren.ginkgo4j.Ginkgo4jRunner;

@RunWith(Ginkgo4jRunner.class)
public class BookTests {
    private Book longBook;
    private Book shortBook;
    {
        Describe("Book", () -> {
            BeforeEach(() -> {
                longBook = new Book("Les Miserables", "Victor Hugo", 1488);
                shortBook = new Book("Fox In Socks", "Dr. Seuss", 24);
       });

       Context("Categorizing book length", () -> {
           Context("With more than 300 pages", () -> {
               It("should be a novel", () -> {
                   assertThat(longBook.categoryByLength(), is("NOVEL"));
               });
           });

           Context("With fewer than 300 pages", () -> {
               It("should be a short story", () -> {
                   assertThat(shortBook.categoryByLength(), is("NOVELLA"));
              });
           });
       });
       });
     }
}

```

Also supports Spring.

(Full disclosure. I am the author of this library).

Lycian answered 17/6, 2016 at 3:22 Comment(0)
S
1

Nice discussion! I did not know JGiven, but I will have a look in it.

In addition, I'm the author of COLA Tests, a new framework that supports full gherkin syntax (precisely the same as Cucumber), it's really easy to setup, specially when compared with JBehave and does not require JUnit runner.

Basically just use whatever libs you are already used to!

Here is an example Spring Controller Test (stories can be loaded from a file):

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = { WebAppContext.class })
public class HelloWorldControllerTest extends BaseColaTest {

    private final String stories =
        "Feature: Introduce REST endpoint\n"
            + "Scenario: Should say hello\n"
            + "Given a web endpoint\n"
            + "When hit by a get request\n"
            + "Then the HTTP status will be OK\n"
            + "And the body will say hello world";

    @Resource
    private WebApplicationContext webApplicationContext;
    private MockMvc mockMvc;
    private ResultActions result;

    @Given("a web endpoint")
    public void given() {
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
    }

    @When("hit by a get request")
    public void when() throws Exception {
        result = mockMvc.perform(get("/helloWorld"));
    }

    @Then("the HTTP status will be OK")
    public void thenOk() throws Exception {
        result.andExpect(status().isOk());
    }

    @Then("the body will say hello world")
    public void thenHello() throws Exception {
        result.andExpect(content().string("Hello World!"));
    }
}
Swob answered 17/1, 2015 at 7:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.