JGiven with Spring

In a previous post we talked about how to create a basic Spring MVC web with junit for test driven development (TDD). Here we are going to include behavior driven development (BDD). To accomplish this goal we will use the JGiven library.

 

Pom.xml configuration

First of all, it is necessary to add it to the pom.xml file:

  <dependency>
    <groupId>org.assertj</groupId>
    <artifactId>assertj-core</artifactId>
    <version>3.5.2</version>
  </dependency>
  <!-- jgiven -->
  <dependency>
    <groupId>com.tngtech.jgiven</groupId>
    <artifactId>jgiven-junit</artifactId>
    <version>0.11.4</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>com.tngtech.jgiven</groupId>
    <artifactId>jgiven-html5-report</artifactId>
    <version>0.11.4</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>com.tngtech.jgiven</groupId>
    <artifactId>jgiven-spring</artifactId>
    <version>0.11.4</version>
    <scope>test</scope>
  </dependency>

Creating the test

Now we can start creating or test.
We will create two new packages in the src/test/java folder.
In com.tngtech.jgiven.integration.spring.scenario we will create our test in a file called BasicModelScenarioTest.java:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = TestSpringConfig.class)
public class BasicModelScenarioTest
		extends SpringScenarioTest<GivenBasicModel, WhenBasicModel, ThenBasicModel> {

	@Test
	public void basic_model_stores_the_given_value() {
		int value = 5;
		given().a_basic_model();
		when().set_$_as_input_value(value);
		then().the_basic_model_value_is(value);
	}
};

This test describes the expected behavior of the BasicModelBean. We have three different Stages:

  • Given: It will define the preconditions. In this case the class GivenBasicModel.java will be only in-charged of instantiate the bean.
  • When: This defines the action that it is applied to the bean. In this case WhenBasicModel.java will set the desired data value.
  • Then: Here are the asserts, inside the class ThenBasicModel.java, which check that the result is the expected one.

The given stage from the class GivenBasicModel.java basically only instantiates the BasicModelBean. This basicModel field is shared with all the different stages because of the @ProvidedScenarioState annotation.

@JGivenStage
public class GivenBasicModel extends Stage<GivenBasicModel> {
	@Autowired
	@ProvidedScenarioState
	BasicModelBean basicModel;

	public GivenBasicModel a_basic_model() {
		return self();
	}
}

The Stage class WhenBasicModel.java calls basicModel.setData(), the value of basicModel is passed from GivenBasicModel:

public class WhenBasicModel extends Stage<WhenBasicModel> {

	@ExpectedScenarioState
	BasicModelBean basicModel;

	public WhenBasicModel set_$_as_data_value(int value) {
		basicModel.setData(value);
		return self();
	}
}

The last class, ThenBasicModel.java assert the desired value in the bean:

public class ThenBasicModel extends Stage<ThenBasicModel> {

	@ExpectedScenarioState
	BasicModelBean basicModel;

	public ThenBasicModel the_basic_model_value_is(int value) {
		assertThat(basicModel.getData()).isEqualTo(value);
		return self();
	}
}

Spring configuration

To make the @Autowired inject the BasicModelBean in the class GivenBasicModel some work is needed. First the @JGivenStage annotation will tell JGiven that this class is a Bean so the injection works.

We also need to create a Configuration class to define where the Beans will be found. This is done in the package com.tngtech.jgiven.integration.spring.config in the file TestSpringConfig.java:

@Configuration
// auto configuration for JGiven
@EnableJGiven
@ComponentScan(basePackages = { "com.testspringmvc.app.data", "com.testspringmvc.app.scenario" })
public class TestSpringConfig {

	@Bean
	public BeanNameAutoProxyCreator jGivenBeanNameAutoProxyCreator() {
		BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
		beanNameAutoProxyCreator
		.setInterceptorNames(new String[] { "springStepMethodInterceptor" });
		return beanNameAutoProxyCreator;
	}
}

And this configuration is invoked in BasicModelScenarioTest.java:

@ContextConfiguration(classes = TestSpringConfig.class)

Execution

Now if we execute this test we will see the scenario report in an human readable form:

user@linuxpc:~/workspace/TestSpringMVC$ mvn test -DBasicModelScenarioTest
[...]
   Given a basic model
    When set 5 as data value
    Then the basic model value is 5
[...]

HTML report

JGiven also can generate really nice reports in html format. In order to do that you need to add the following plugin to the pom.xml file:

    <plugin>
      <groupId>com.tngtech.jgiven</groupId>
      <artifactId>jgiven-maven-plugin</artifactId>
      <executions>
        <execution>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
      <configuration>
        <format>html</format>
      </configuration>
    </plugin>

The reports are generated when executing mvn verify and are stored in target/jgiven-reports in html and json format.

user@linuxpc:~/workspace/TestSpringMVC$ mvn verify

References:

JGiven: http://jgiven.org/
SourceCode: https://github.com/calabozo/TestSpringMVC

Advertisements

2 thoughts on “JGiven with Spring

  1. Thanks for these nice tips.

    Now, i would like to generate tag hrefs using a dedicated “issue.url” property configured in some “config.properties” file loaded by a Spring property placeholder.

    Indeed, JGiven allows us to implement our own TagDescriptionGenerator implementations but i can’t figure out how to inject/refer Spring’s Environment instance to retrieve my property.
    I’ve eventually been forced to use some static Environment instance in order to be able to use it from anywhere in my code, but that is not very clean.

    Well, in case you got any tips about this …

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s