How to run JUnit SpringJUnit4ClassRunner with Parametrized? How to run JUnit SpringJUnit4ClassRunner with Parametrized? spring spring

How to run JUnit SpringJUnit4ClassRunner with Parametrized?


You can use SpringClassRule and SpringMethodRule - supplied with Spring

import org.junit.ClassRule;import org.junit.Rule;import org.junit.Test;import org.junit.runner.RunWith;import org.junit.runners.Parameterized;import org.springframework.test.context.junit4.rules.SpringClassRule;import org.springframework.test.context.junit4.rules.SpringMethodRule;@RunWith(Parameterized.class)@ContextConfiguration(...)public class MyTest {    @ClassRule    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();    @Rule    public final SpringMethodRule springMethodRule = new SpringMethodRule();    ...


There are at least 2 options to do that:

  1. Following http://www.blog.project13.pl/index.php/coding/1077/runwith-junit4-with-both-springjunit4classrunner-and-parameterized/

    Your test needs to look something like this:

     @RunWith(Parameterized.class) @ContextConfiguration(classes = {ApplicationConfigTest.class}) public class ServiceTest {     private TestContextManager testContextManager;     @Before     public void setUpContext() throws Exception {         //this is where the magic happens, we actually do "by hand" what the spring runner would do for us,        // read the JavaDoc for the class bellow to know exactly what it does, the method names are quite accurate though       this.testContextManager = new TestContextManager(getClass());       this.testContextManager.prepareTestInstance(this);     }     ... }
  2. There is a github project https://github.com/mmichaelis/spring-aware-rule, which builds on previous blog, but adds support in a generalized way

    @SuppressWarnings("InstanceMethodNamingConvention")@ContextConfiguration(classes = {ServiceTest.class})public class SpringAwareTest {    @ClassRule    public static final SpringAware SPRING_AWARE = SpringAware.forClass(SpringAwareTest.class);    @Rule    public TestRule springAwareMethod = SPRING_AWARE.forInstance(this);    @Rule    public TestName testName = new TestName();    ...}

So you can have a basic class implementing one of the approaches, and all tests inheriting from it.


There is another solution with JUnit 4.12 without the need of Spring 4.2+.

JUnit 4.12 introduces ParametersRunnerFactory which allow to combine parameterized test and Spring injection.

public class SpringParametersRunnerFactory implements ParametersRunnerFactory {@Override  public Runner createRunnerForTestWithParameters(TestWithParameters test) throws InitializationError {    final BlockJUnit4ClassRunnerWithParameters runnerWithParameters = new BlockJUnit4ClassRunnerWithParameters(test);    return new SpringJUnit4ClassRunner(test.getTestClass().getJavaClass()) {      @Override      protected Object createTest() throws Exception {        final Object testInstance = runnerWithParameters.createTest();        getTestContextManager().prepareTestInstance(testInstance);        return testInstance;      }    };  }}

The factory can be added to test class to give full Spring support like test transaction, reinit dirty context and servlet test.

@UseParametersRunnerFactory(SpringParametersRunnerFactory.class)@RunWith(Parameterized.class)@ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})@WebAppConfiguration@Transactional@TransactionConfigurationpublic class MyTransactionalTest {  @Autowired  private WebApplicationContext context;  ...}

If you need Spring context inside @Parameters static method to provide parameters to test instances, please see my answer here How can I use the Parameterized JUnit test runner with a field that's injected using Spring?.