Le code suivant n'est pas valide en raison d'une annotation @RunWith
en double:
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(Parameterized.class)
@SpringApplicationConfiguration(classes = {ApplicationConfigTest.class})
public class ServiceTest {
}
Mais comment puis-je utiliser ces deux annotations conjointement?
Il y a au moins 2 options pour le faire:
Votre test doit ressembler à ceci:
@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);
}
...
}
Il existe un projet github https://github.com/mmichaelis/spring-aware-rule , qui repose sur le blog précédent, mais ajoute le support de manière générale.
@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();
...
}
Ainsi, vous pouvez avoir une classe de base implémentant l’une des approches et tous les tests qui en héritent.
Vous pouvez utiliser SpringClassRule et SpringMethodRule - fournies avec 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();
...
Il existe une autre solution avec JUnit 4.12 sans la nécessité de Spring 4.2+.
JUnit 4.12 introduit ParametersRunnerFactory qui permet de combiner test paramétré et injection Spring.
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;
}
};
}
}
L'usine peut être ajoutée à la classe de test pour fournir un support Spring complet tel que transaction de test , réinitie le contexte sale et test de servlet .
@UseParametersRunnerFactory(SpringParametersRunnerFactory.class)
@RunWith(Parameterized.class)
@ContextConfiguration(locations = {"/test-context.xml", "/mvc-context.xml"})
@WebAppConfiguration
@Transactional
@TransactionConfiguration
public class MyTransactionalTest {
@Autowired
private WebApplicationContext context;
...
}
Si vous avez besoin du contexte Spring dans @Parameters static pour fournir les paramètres permettant de tester les instances, veuillez consulter ma réponse ici Comment utiliser le programme de test JUnit paramétré avec un champ injecté avec Spring? .
Ce qui a fonctionné pour moi, c’est de disposer d’une classe de test @RunWith(Parameterized.class)
qui gère le contexte de l’application "à la main".
Pour ce faire, j'ai créé un contexte d'application avec la même collection de chaînes que dans le @ContextConfiguration
. Donc au lieu d'avoir
@ContextConfiguration(locations = { "classpath:spring-config-file1.xml",
"classpath:spring-config-file2.xml" })
J'ai eu
ApplicationContext ctx = new ClassPathXmlApplicationContext(new String[] {
"classpath:spring-config-file1.xml", "classpath:spring-config-file2.xml" });
Et pour chaque @Autowired dont j'avais besoin, je l'ai récupéré à la main dans le contexte créé:
SomeClass someBean = ctx.getBean("someClassAutowiredBean", SomeClass.class);
N'oubliez pas de fermer le contexte à la fin:
((ClassPathXmlApplicationContext) ctx).close();