junitparams-spring-integration-example icon indicating copy to clipboard operation
junitparams-spring-integration-example copied to clipboard

Example of JUnitParams integration with Spring

JUnitParams integration with Spring

Problems with integration SpringJUnit4ClassRunner with JUnitParamsRunner

There was a known problem with running tests which start spring context combined with JUnitParams. Main reason was that running spring tests required usage of runner SpringJUnit4ClassRunner and it eliminates option to use JUnitParamsRunner. JUnitParams runner must be top junit runner. Combining it with spring was impossible until now.

Alternative way to start spring context

Since spring version 4.2 there were introduced two classes that help us start spring without any special runner defined:

According to its documentation to fully replace SpringJUnit4ClassRunner we need to always defined both of these rules because first supports all annotations at class level and second all annotations at instance and method level.

Example test which uses this mechanism can be modified version of CalculationEndpointTest but without all annotations related to JUnitParams.

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CalculationEndpointTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Test
    public void spring_injection() throws Exception {
        assertThat(restTemplate).isNotNull();
    }

}

Running JUnitParamsRunner with spring

Now it is easy to combine JUnitParamsRunner with spring. As demonstrated in CalculationEndpointTest we just need to add proper JUnitParams annotations. Example is quite straightforward. It starts spring boot application with simple rest controller which takes json as parameter and multiplies passed multiplier and value and returns it as json response. We supply test (with @Parameters annotation) with set of multiplier value and expected multiplied value f.e. 2, 3, 6 which means we expect 6 out of multiplication of 2 and 3. Started spring boot indicates that annotation @SpringBootTest was applied as well as injecting restTemplate with @Autowired.

@RunWith(JUnitParamsRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class CalculationEndpointTest {

    @Autowired
    private TestRestTemplate restTemplate;

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @Test
    @Parameters({
            "2, 3, 6",
            "3, 3, 9",
            "0, 3, 0",
            "3, 0, 0"
    })
    public void multiply_values(int multiplier, int value, int expectedMultipliedValue) throws Exception {
        MultiplyOperationResponseJson multiplyOperationResponseJson = restTemplate.postForObject(
                "/multiply/", new MultiplyOperationRequestJson(multiplier, value), MultiplyOperationResponseJson.class
        );

        assertThat(multiplyOperationResponseJson.multipliedValue).isEqualTo(expectedMultipliedValue);
    }
}

Older version of spring and JUnitParams

What if you are using older version of spring and you can not migrate to newer one. Generally it is possible to implement SpringClassRule and SpringMethodRule by copying them from spring 4.2 to your project. You will also need to copy class RunPrepareTestInstanceCallbacks.

In SpringClassRule you need to remove line

statement = withProfileValueCheck(statement, testClass);

from apply method (and related methods code).

In SpringMethodRule you need also small modifications. Remove

statement = withPotentialRepeat(statement, frameworkMethod, testInstance);
statement = withPotentialTimeout(statement, frameworkMethod, testInstance);
statement = withProfileValueCheck(statement, frameworkMethod, testInstance);

from apply method (and related methods code).

Thanks to these you can now use your own created rules but as you see you are losing support for annotations:

  • @Repeat
  • @IfProfileValue
  • @Timed

If you have any problems with these modifications let us know.