200 votes

Comment tester du code dépendant de variables d'environnement avec JUnit ?

J'ai un morceau de code Java qui utilise une variable d'environnement et le comportement du code dépend de la valeur de cette variable. J'aimerais tester ce code avec différentes valeurs de la variable d'environnement. Comment puis-je faire cela dans JUnit ?

J'ai vu quelques façons de définir des variables d'environnement en Java en général, mais je suis plus intéressé par l'aspect des tests unitaires, surtout si l'on considère que les tests ne devraient pas interférer les uns avec les autres.

2voto

Vous pouvez utiliser Powermock pour s'être moqué de l'appel. Comme :

PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("MyEnvVariable")).thenReturn("DesiredValue");

Vous pouvez également simuler tous les appels avec :

PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv(Mockito.anyString())).thenReturn(envVariable);

1voto

Ashley Frieze Points 1

La bibliothèque https://github.com/webcompere/system-stubs/tree/master/system-stubs-jupiter - une fourchette de system-lambda - fournit un plug-in JUnit 5 :

@ExtendWith(SystemStubsExtension.class)
class SomeTest {
    @SystemStub
    private EnvironmentVariables environmentVariables =
       new EnvironmentVariables("name", "value");

    @Test
    void someTest() {
       // environment is set here

       // can set a new value into the environment too
       environmentVariables.set("other", "value");

       // tidy up happens at end of this test
    }

}

En https://junit-pioneer.org/ nécessite que les valeurs des variables d'environnement soient connues au moment de la compilation. Ce qui précède permet également de définir de variables d'environnement dans le @BeforeAll ce qui signifie qu'il interagit bien avec des éléments tels que Testcontainers qui pourrait mettre en place certaines ressources nécessaires aux tests sur les enfants.

0voto

Ola Aronsson Points 21

Les suggestions ci-dessus mettent beaucoup l'accent sur l'invention de solutions. en cours d'exécution pour passer des variables, les définir et les effacer, etc ? Mais pour tester les choses "structurellement", je suppose que vous voulez avoir différentes suites de tests pour différents scénarios ? C'est un peu comme lorsque vous voulez exécuter vos tests d'intégration les plus lourds, alors que dans la plupart des cas, vous voulez simplement les ignorer. Mais alors vous n'essayez pas "d'inventer des façons de régler les choses en cours d'exécution", plutôt vous vous contentez de dire maven ce que vous voulez ? Il y avait beaucoup de travail pour dire à maven d'exécuter des tests spécifiques via des profils et autres, si vous cherchez sur Google, les gens suggèrent de le faire via springboot (mais si vous n'avez pas intégré le monstrum springboot dans votre projet, cela semble être une empreinte horrible pour "juste exécuter JUnits", n'est-ce pas ?) Ou bien cela impliquerait des tas de jongleries XML POM plus ou moins gênantes, ce qui est également fastidieux et, disons-le, "un mouvement des années 90", aussi gênant que d'insister encore pour faire des "spring beans à partir de XML", en montrant vos "spring beans". ultime 600 ligne logback.xml ou autre... ?

Aujourd'hui, vous pouvez simplement utiliser Junit 5 (cet exemple est pour maven, plus de détails peuvent être trouvés ici). Guide d'utilisation de JUnit 5 5 )

 <dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.junit</groupId>
            <artifactId>junit-bom</artifactId>
            <version>5.7.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

et ensuite

    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <scope>test</scope>
    </dependency>

puis, dans votre librairie utilitaire préférée, créez une classe d'annotation simple et astucieuse telle que

@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@EnabledIfEnvironmentVariable(named = "MAVEN_CMD_LINE_ARGS", matches = "(.*)integration-testing(.*)")
public @interface IntegrationTest {}

Ainsi, chaque fois que vos options cmdline contiennent -Pintegration-testing par exemple, alors et seulement alors votre classe/méthode de test annotée @IntegrationTest se déclenchera. Ou, si vous ne voulez pas utiliser (et configurer) un profil maven spécifique mais plutôt passer des propriétés de système 'trigger' au moyen de la commande

mvn <cmds> -DmySystemPop=mySystemPropValue

et adapter votre interface d'annotation pour la déclencher (oui, il existe aussi une propriété @EnabledIfSystemProperty). Vous pouvez aussi vous assurer que votre shell est configuré pour contenir "ce dont vous avez besoin" ou, comme suggéré plus haut, vous pouvez vous donner la peine d'ajouter system env via votre POM XML.

Avoir son code à l'intérieur En effet, il est facile d'imaginer que quelqu'un fera tôt ou tard une erreur interne "cachée" qui passera inaperçue pendant un certain temps, pour surgir soudainement et vous mordre de plein fouet dans la production plus tard . Vous préférez généralement une approche qui implique qu'une "entrée donnée" donne une "sortie attendue", quelque chose qui est facile à comprendre et à maintenir dans le temps, vos collègues codeurs le verront simplement "immédiatement".

Bien longue "réponse" ou peut-être plutôt une simple opinion sur les raisons pour lesquelles vous préférez cette approche (oui, au début j'ai juste lu le titre de cette question et je me suis lancé pour y répondre, c'est-à-dire "Comment tester du code dépendant de variables d'environnement à l'aide de JUnit").

0voto

Tihamer Points 41

Une méthode lente, fiable et ancienne qui fonctionne toujours dans tous les systèmes d'exploitation et dans toutes les langues (et même entre les langues) consiste à écrire les données "système/environnement" dont vous avez besoin dans un fichier texte temporaire, à les lire lorsque vous en avez besoin, puis à les effacer. Bien entendu, si vous travaillez en parallèle, il vous faut des noms uniques pour le fichier, et si vous y mettez des informations sensibles, vous devez les crypter.

0voto

Yajli Maclo Points 926

Simplement

Ajouter la dépendance maven ci-dessous

<!-- for JUnit 4 -->
<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-junit4</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

<!-- for JUnit 5 -->
<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-jupiter</artifactId>
    <version>1.1.0</version>
    <scope>test</scope>
</dependency>

Dans votre test, vous pouvez utiliser quelque chose de similaire :

@Rule
public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule();

@Test
public void givenEnvironmentCanBeModified_whenSetEnvironment_thenItIsSet() {
    // mock that the system contains an  environment variable "ENV_VAR" having value "value1"
    environmentVariablesRule.set("ENV_VAR", "value1");

    assertThat(System.getenv("ENV_VAR")).isEqualTo("value1");
}

Référence pour plus de détails
https://www.baeldung.com/java-system-stubs

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X