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:
-
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); } ... }
-
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
@TransactionConfiguration
public 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?.