web-dev-qa-db-fra.com

Tests d'intégration de printemps avec profil

Dans nos applications Web Spring, nous utilisons les profils de bean Spring pour différencier trois scénarios: développement, intégration et production. Nous les utilisons pour nous connecter à différentes bases de données ou définir d'autres constantes.

L'utilisation des profils Spring Bean fonctionne très bien pour changer l'environnement de l'application Web.

Le problème que nous avons, c'est quand notre code de test d'intégration doit changer pour l'environnement. Dans ces cas, le test d'intégration charge le contexte d'application de l'application Web. De cette façon, nous n'avons pas à redéfinir les connexions à la base de données, les constantes, etc. (en appliquant le principe DRY).

Nous configurons nos tests d'intégration comme suit.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ["classpath:applicationContext.xml"])
public class MyTestIT
{
   @Autowired
   @Qualifier("myRemoteURL")  // a value from the web-app's applicationContext.xml
   private String remoteURL;
   ...
 }

Je peux le faire fonctionner localement en utilisant @ActiveProfiles, mais cela est codé en dur et entraîne l'échec de nos tests sur le serveur de génération.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = ["classpath:applicationContext.xml"])
@ActiveProfiles("development")
public class MyTestIT
{ ... }

J'ai également essayé d'utiliser le @WebAppConfiguration en espérant qu'il pourrait en quelque sorte importer le spring.profiles.active propriété de Maven, mais cela ne fonctionne pas.

Une autre remarque, nous devons également configurer notre code afin que les développeurs puissent exécuter l'application Web, puis exécuter les tests à l'aide du lanceur de test d'IntelliJ (ou d'un autre IDE). Ceci est beaucoup plus facile pour le débogage des tests d'intégration.

21
David V

Comme d'autres personnes l'ont déjà souligné, vous pouvez choisir d'utiliser Maven pour définir le spring.profiles.active propriété système, en vous assurant pas d'utiliser @ActiveProfiles, mais ce n'est pas pratique pour les tests exécutés dans l'EDI.

Pour un moyen programmatique de définir les profils actifs, vous avez quelques options.

  1. Spring 3.1: écrire un ContextLoader personnalisé qui prépare le contexte en définissant des profils actifs dans le Environment du contexte.
  2. Spring 3.2: un ContextLoader personnalisé reste une option, mais un meilleur choix est d'implémenter un ApplicationContextInitializer et de le configurer via l'attribut initializers de @ContextConfiguration. Votre initialiseur personnalisé peut configurer le Environment en définissant par programme les profils actifs.
  3. Spring 4.0: les options susmentionnées existent toujours; cependant, depuis Spring Framework 4.0, il existe une nouvelle API ActiveProfilesResolver dédiée exactement à cette fin: pour déterminer par programme l'ensemble de profils actifs à utiliser dans un test. Un ActiveProfilesResolver peut être enregistré via l'attribut resolver de @ActiveProfiles.

Cordialement,

Sam (auteur du Spring TestContext Framework)

37
Sam Brannen

J'ai eu un problème similaire: je voulais exécuter tous mes tests d'intégration avec un profil par défaut, mais permettre à un utilisateur de remplacer avec un profil qui représentait un environnement différent ou même une saveur db sans avoir à modifier la valeur @ActiveProfiles. Cela est possible si vous utilisez Spring 4.1+ avec un ActiveProfilesResolver personnalisé.

Cet exemple de résolveur recherche une propriété système, spring.profiles.active, et s'il n'existe pas, il déléguera au résolveur par défaut qui utilise simplement l'annotation @ActiveProfiles.

public class SystemPropertyActiveProfileResolver implements ActiveProfilesResolver {

private final DefaultActiveProfilesResolver defaultActiveProfilesResolver = new DefaultActiveProfilesResolver();

@Override
public String[] resolve(Class<?> testClass) {

    if(System.getProperties().containsKey("spring.profiles.active")) {

        final String profiles = System.getProperty("spring.profiles.active");
        return profiles.split("\\s*,\\s*");

    } else {

        return defaultActiveProfilesResolver.resolve(testClass);
    }
}

}

Et dans vos classes de test, vous l'utiliseriez comme ceci:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles( profiles={"h2","xyz"},
resolver=SystemPropertyActiveProfileResolver.class)
public class MyTest { }

Vous pouvez bien sûr utiliser d'autres méthodes en plus de vérifier l'existence d'une propriété système pour définir les profils actifs. J'espère que cela aide quelqu'un.

16
Jim Cox

Si vous voulez éviter de coder en dur le profil, vous pouvez utiliser la propriété systèmespring.profiles.active et réglez-le sur tout ce dont vous avez besoin dans cet environnement particulier, par exemple nous avons des profils "dev", "stage" et "prod" pour nos différents environnements; nous avons également des profils "test", "test-local" et "test-server" pour nos tests.

N'oubliez pas que vous pouvez avoir plusieurs profils dans cette propriété système en utilisant une liste de valeurs séparées par des virgules, par exemple "test, test-qa".

Vous pouvez spécifier les propriétés du système dans un projet maven dans le plugin maven surefire ou les transmettre comme ceci:

mvn -DargLine="-DpropertyName=propertyValue"
5
ElderMael

Comme @ElderMael l'a mentionné, vous pouvez utiliser la propriété argLine du plugin maven surefire. Souvent, lorsque je dois exécuter tout le test avec différents profils Spring spécifiques, je définis un profil Maven supplémentaire. Exemple:

<profiles>
    <profile>
        <id>foo</id>
        <dependencies>
            <!-- additional dependencies if needed, i.e. database drivers ->
        </dependencies>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.Apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <argLine>-Dspring.profiles.active=foo</argLine>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Avec cette approche, vous pouvez facilement exécuter tous les tests avec le profil activé par la commande maven:

mvn clean test -Pfoo

L'annotation @ActiveProfile est bonne mais parfois nous devons exécuter tout le test avec des profils spécifiques activés et avec des paramètres @ActiveProfile codés en dur, c'est un problème.

Par exemple: par défaut, test d'intégration avec la base de données H2 en mémoire, mais parfois vous voulez exécuter le test sur la "vraie" base de données. Vous pouvez définir ce profil maven supplémentaire et définir le travail Jenkins. Avec SpringBoot, vous pouvez également mettre des propriétés supplémentaires à tester/ressources avec le nom application-foo.yml (ou propriétés) et ces propriétés seront prises en compte pour.

2
Przemek Nowak