J'ai une application Web où le problème typique est qu'elle nécessite différents fichiers de configuration pour différents environnements. Certaines configurations sont placées sur le serveur d'applications en tant que sources de données JNDI. Cependant, certaines configurations restent dans les fichiers de propriétés.
Par conséquent, je souhaite utiliser la fonctionnalité Profils de ressort.
Mon problème est que le scénario de test ne fonctionne pas.
context.xml:
<context:property-placeholder
location="classpath:META-INF/spring/config_${spring.profiles.active}.properties"/>
Cas de test:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
TestPreperationExecutionListener.class
})
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration(locations = {
"classpath:context.xml" })
public class TestContext {
@Test
public void testContext(){
}
}
Le problème semble être que la variable de chargement du profil n'est pas résolue:
Caused by: Java.io.FileNotFoundException: class path resource [META-INF/spring/config_${spring.profiles.active}.properties] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.Java:157)
at org.springframework.core.io.support.PropertiesLoaderSupport.loadProperties(PropertiesLoaderSupport.Java:181)
at org.springframework.core.io.support.PropertiesLoaderSupport.mergeProperties(PropertiesLoaderSupport.Java:161)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.postProcessBeanFactory(PropertySourcesPlaceholderConfigurer.Java:138)
... 31 more
Le profil actuel doit être défini avec l'annotation @ActiveProfile
. Comme c'est un test, je ne pourrai pas utiliser le web.xml
. Si possible, j'aimerais également éviter les options d'exécution. Le test doit être exécuté tel quel (si possible).
Comment puis-je activer correctement le profil? Est-il possible de définir le profil avec un fichier context.xml? Puis-je déclarer la variable dans un fichier test-context.xml qui appelle le contexte normal?
Puis-je vous recommander de le faire de cette façon, définissez votre test comme suit:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
TestPreperationExecutionListener.class
})
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration
public class TestContext {
@Test
public void testContext(){
}
@Configuration
@PropertySource("classpath:/myprops.properties")
@ImportResource({"classpath:context.xml" })
public static class MyContextConfiguration{
}
}
avec le contenu suivant dans le fichier myprops.properties:
spring.profiles.active=localtest
Avec cela, votre deuxième fichier de propriétés devrait être résolu:
META-INF/spring/config_${spring.profiles.active}.properties
En regardant la réponse de Biju, j'ai trouvé une solution efficace.
J'ai créé un fichier contextuel supplémentaire test-context.xml
:
<context:property-placeholder location="classpath:config/spring-test.properties"/>
Contenant le profil:
spring.profiles.active=localtest
Et en chargeant le test avec:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
TestPreperationExecutionListener.class
})
@Transactional
@ActiveProfiles(profiles = "localtest")
@ContextConfiguration(locations = {
"classpath:config/test-context.xml" })
public class TestContext {
@Test
public void testContext(){
}
}
Cela économise du travail lors de la création de plusieurs cas de test.
La meilleure approche consiste à supprimer l'annotation @ActiveProfiles et à effectuer les opérations suivantes:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({
TestPreperationExecutionListener.class
})
@Transactional
@ContextConfiguration(locations = {
"classpath:config/test-context.xml" })
public class TestContext {
@BeforeClass
public static void setSystemProperty() {
Properties properties = System.getProperties();
properties.setProperty("spring.profiles.active", "localtest");
}
@AfterClass
public static void setSystemProperty() {
System.clearProperty("spring.profiles.active");
}
@Test
public void testContext(){
}
}
Et votre test-context.xml devrait avoir les éléments suivants:
<context:property-placeholder
location="classpath:META-INF/spring/config_${spring.profiles.active}.properties"/>
public class LoginTest extends BaseTest {
@Test
public void exampleTest( ){
// Test
}
}
Hérite d'une classe de test de base (cet exemple est testng
plutôt que jUnit
, mais ActiveProfiles
est identique):
@ContextConfiguration(locations = { "classpath:spring-test-config.xml" })
@ActiveProfiles(resolver = MyActiveProfileResolver.class)
public class BaseTest extends AbstractTestNGSpringContextTests { }
MyActiveProfileResolver
peut contenir toute logique nécessaire pour déterminer le profil à utiliser:
public class MyActiveProfileResolver implements ActiveProfilesResolver {
@Override
public String[] resolve(Class<?> aClass) {
// This can contain any custom logic to determine which profiles to use
return new String[] { "exampleProfile" };
}
}
Ceci définit le profil qui est ensuite utilisé pour résoudre les dépendances requises par le test.