Here is a first solution without JUnit 4.12 parameterized factory, below an improved solution with it.
Static context without transactional support
Let Spring do all configuration parsing and autowiring with TestContextManager class.
The trick is to use a fake test instance to get autowired fields and pass them to the parameterized test which will effectively run.
But keep in mind prepareTestInstance() do the autowiring but doesn't manage test transaction and other nice stuffs handled by beforeTestMethod() and afterTestMethod().
@RunWith(Parameterized.class)
@ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
@WebAppConfiguration
@ActiveProfiles("test-profile")
public class MyTest {
@Parameters
public static Collection<Object[]> params() throws Exception {
final MyTest fakeInstance = new MyTest();
final TestContextManager contextManager = new TestContextManager(MyTest.class);
contextManager.prepareTestInstance(fakeInstance);
final WebApplicationContext context = fakeInstance.context;
// Do what you need with Spring context, you can even access web resources
final Resource[] files = context.getResources("path/files");
final List<Object[]> params = new ArrayList<>();
for (Resource file : files) {
params.add(new Object[] {file, context});
}
return params;
}
@Parameter
public Resource file;
@Autowired
@Parameter(1)
public WebApplicationContext context;
}
However a drawback appear if you have a lot of autowired fields because you have to manually pass them to the array parameters.
Parameterized factory with full Spring support
JUnit 4.12 introduce 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 previous test class to give full Spring support like test transaction, reinit dirty context and servlet test. And of course there no more need to pass autowired fields from fake test instance to parameterized test.
@UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
@RunWith(Parameterized.class)
@ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
@WebAppConfiguration
@Transactional
@TransactionConfiguration
public class MyTransactionalTest {
@Parameters
public static Collection<Object[]> params() throws Exception {
final MyTransactionalTest fakeInstance = new MyTransactionalTest();
final TestContextManager contextManager = new TestContextManager(MyTransactionalTest.class);
contextManager.prepareTestInstance(fakeInstance);
final WebApplicationContext context = fakeInstance.context;
// Do what you need with Spring context, you can even access web resources
final Resource[] files = context.getResources("path/files");
final List<Object[]> params = new ArrayList<>();
for (Resource file : files) {
params.add(new Object[] {file});
}
return params;
}
@Parameter
public Resource file;
@Autowired
private WebApplicationContext context;
}