web-dev-qa-db-fra.com

Profils de printemps et essais

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?

37
Udo Held

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
33
Biju Kunjummen

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.

5
Udo Held

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"/>
2
codebusta
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.

0
psych