6

I am looking for BDD java framework with possibility to reuse Given & Then for Unit and Integration tests.

In other words 1. Given some precondition. 2. When - depending on the environment 3. Then verify results of When

I want to be able by changing When, and keeping Given and Then intact, change the type of the test, for example in simple REST service:

  1. UNIT test
    • Given
      • generates some POJO object
    • When
      • receives POJO from Given
      • calls internal service with this POJO
      • receives result in POJO form from the service
      • forwards received POJO to Then
    • Then
      • verifies POJO from When
  2. INTEGRATION test
    • Given
      • generates some POJO object
    • When
      • receives POJO from Given
      • encrypts POJO in external service format
      • calls external service
      • receives result in external service format from exposed service
      • transforms received result in POJO
      • forwards received POJO to Then
    • Then
      • verifies POJO from When

So in example, Given and Then behave the same way, for both integration and unit tests, and by simply changin When the scope of the test goes from UNIT to INTEGRATION.

Can someone point me in the right direction?

I don't want to reinvent the wheel

mavarazy
  • 7,562
  • 1
  • 34
  • 60
  • 1
    There is a good discussion about BDD frameworks in Java on stackoverflow here: http://stackoverflow.com/questions/1068785/what-are-the-differences-between-bdd-frameworks-for-java – Tomasz Stanczak Feb 12 '13 at 09:07

3 Answers3

8

Disclamer: I am the author of JGiven.

JGiven exactly provides that. It is a BDD framework for Java where scenarios are built by so-called stage classes. For your example you need four stage classes: GivenInput, WhenInternalService, WhenExternalService, and ThenOutput. Then you can write two tests:

Unit test for the internal service:

public class InternalServiceTest extends 
       ScenarioTest<GivenInput, WhenInternalService, ThenOutput> {

    @Test
    public void internal_service_works_as_expected() {
       given().some_input();
       when().the_internal_service_is_called();
       then().the_result_is_correct();
    } 
}

Integration test for the external service:

public class ExternalServiceTest extends 
       ScenarioTest<GivenInput, WhenExternalService, ThenOutput> {

    @Test
    public void external_service_works_as_expected() {
       given().some_input();
       when().the_external_service_is_called();
       then().the_result_is_correct();
    } 
}

The stage classes then look something like this:

public class GivenInput extends Stage<GivenInput> {
    @ProvidedScenarioState
    InputPojo input;

    public GivenInput some_input() {
       input = new InputPojo();
       return self();
    }
}

public class WhenInternalService extends Stage<WhenInternalService> {
    @ExpectedScenarioState
    InputPojo input;

    @ProvidedScenarioState
    OutputPojo output;

    public WhenInternalService the_internal_service_is_called() {
        output = new InternalService().invoke(input);
        return self();
    }
}

public class WhenExternalService extends Stage<WhenExternalService> {
    @ExpectedScenarioState
    InputPojo input;

    @ProvidedScenarioState
    OutputPojo output;

    public WhenExternalService the_external_service_is_called() {
        ExternalInput externalInput = transformToExternal(input);
        ExternalOutput externalOutput = new ExternalService().invoke(external);
        output = transformToInternal(externalOutput);
        return self();
    }
}

public class ThenOutput extends Stage<ThenOutput> {
    @ExpectedScenarioState
    OutputPojo output;

    public ThenOutput the_result_is_correct() {
        assertThat(output).isNotNull();
        return self();
    }
}

Note that the step methods are written in a fluent-interface style to be able to chain multiple conditions (not needed in your example though).

Jan Schaefer
  • 1,882
  • 1
  • 18
  • 23
1

If you're using Java 8 then you should have a look at this github project.

Using this you could achieve what you want without the hassle of creating classes. This is due to the use of Generics + Java 8 Lambdas.

Here are some basic test samples:

@Test
public void basicFlowTest() {
 given(1)
  .when("multiplying by 2", givenValue -> 2 * givenValue)
  .then("value should be even", whenValue -> whenValue % 2 == 0);
}

public void multiTypeFlowTest() {
 LocalDateTime localDateTime = LocalDateTime.now();
 DayOfWeek expectedDay = localDateTime.getDayOfWeek();

 given(localDateTime)
  .when("retrieving current day", date -> date.getDayOfWeek())
  .then("days should match", day -> expectedDay == day);
}

@Test
public void assertFlowTest() {
 Integer primeNumber = 17;
 given("a prime number", primeNumber)
  .when("finding dividers naively", number -> IntStream.rangeClosed(1, number)
   .boxed().filter(value -> number % value == 0).collect(Collectors.toList()))
  .then(dividers -> {
   assertEquals("should have two dividers", 2, dividers.size());
   assertEquals("first divider should be 1", 1, (int) dividers.get(0));
   assertEquals(String.format("first divider should be %d", primeNumber), primeNumber, dividers.get(1));
  });
}
0

JUnit?

It's quite possible to have an abstract base-class with a @Before method (i.e. "Given") and a common method with assertions (i.e. "Then").

pap
  • 27,064
  • 6
  • 41
  • 46