web-dev-qa-db-fra.com

Comment tester le code dépendant des variables d'environnement à l'aide de 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 les tests unitaires, en particulier étant donné que les tests ne doivent pas interférer les uns avec les autres.

103
vitaut

La bibliothèque System Rules fournit une règle JUnit pour la définition de variables d’environnement.

import org.junit.contrib.Java.lang.system.EnvironmentVariables;

public void EnvironmentVariablesTest {
  @Rule
  public final EnvironmentVariables environmentVariables
    = new EnvironmentVariables();

  @Test
  public void setEnvironmentVariable() {
    environmentVariables.set("name", "value");
    assertEquals("value", System.getenv("name"));
  }
}

Disclaimer: Je suis l'auteur de règles système.

144
Stefan Birkner

La solution habituelle consiste à créer une classe qui gère l’accès à cette variable d’environnement, que vous pouvez ensuite simuler dans votre classe de test.

public class Environment {
    public String getVariable() {
        return System.getenv(); // or whatever
    }
}

public class ServiceTest {
    private static class MockEnvironment {
        public String getVariable() {
           return "foobar";
        }
    }

    @Test public void testService() {
        service.doSomething(new MockEnvironment());
    }
}

La classe sous test obtient ensuite la variable d'environnement à l'aide de la classe Environment et non directement à partir de System.getenv ().

62
Matthew Farwell

Dans une situation similaire comme celle-ci, je devais écrire un cas de test qui dépend de variable d'environnement , j'ai essayé de suivre:

  1. Je suis allé pour Règles du système comme suggéré par Stefan Birkner. Son utilisation était simple. Mais plus tôt que plus tard, j'ai trouvé le comportement erratique. En une exécution, cela fonctionne, mais à la prochaine exécution, il échoue. J'ai examiné et constaté que les règles système fonctionnaient bien avec JUnit version 4 ou supérieure. Mais dans mon cas, j’utilisais des binaires qui dépendaient de JUnit 3 . J'ai donc sauté les règles du système . Vous en trouverez plus ici L'annotation @ Rule ne fonctionne pas avec TestSuite dans JUnit .
  2. Ensuite, j'ai essayé de créer une variable d'environnement via la classe Builder fournie par Java . Ici, à travers Java Code, nous pouvons créer une variable d’environnement, mais vous devez connaître le processus ou programme nom que je n'ai pas nommé. En outre, il crée une variable d'environnement pour le processus enfant, pas pour le processus principal.

J'ai perdu une journée en utilisant les deux approches ci-dessus, mais en vain. Puis Maven est venu à ma rescousse. Nous pouvons définir des variables d'environnement ou Propriétés système via Maven POM fichier que je pense la meilleure façon de faire Test unitaire pour Projet basé sur Maven . Ci-dessous est l'entrée que j'ai faite dans le fichier [~ # ~] pom [~ # ~] .

    <build>
      <plugins>
       <plugin>
        <groupId>org.Apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
          <systemPropertyVariables>
              <PropertyName1>PropertyValue1</PropertyName1>                                                          
              <PropertyName2>PropertyValue2</PropertyName2>
          </systemPropertyVariables>
          <environmentVariables>
            <EnvironmentVariable1>EnvironmentVariableValue1</EnvironmentVariable1>
            <EnvironmentVariable2>EnvironmentVariableValue2</EnvironmentVariable2>
          </environmentVariables>
        </configuration>
      </plugin>
    </plugins>
  </build>

Après ce changement, j'ai exécuté à nouveau des cas de test et tout a soudainement fonctionné comme prévu. Pour l'information du lecteur, j'ai exploré cette approche dans Maven 3.x , donc je n'ai aucune idée de Maven 2. x .

14
RLD

Je ne pense pas que cela ait été mentionné pour le moment, mais vous pouvez également utiliser Powermockito:

Donné:

package com.foo.service.impl;

public class FooServiceImpl {

    public void doSomeFooStuff() {
        System.getenv("FOO_VAR_1");
        System.getenv("FOO_VAR_2");
        System.getenv("FOO_VAR_3");

        // Do the other Foo stuff
    }
}

Vous pouvez faire ce qui suit:

package com.foo.service.impl;

import static org.mockito.Mockito.when;
import static org.powermock.api.mockito.PowerMockito.mockStatic;
import static org.powermock.api.mockito.PowerMockito.verifyStatic;

import org.junit.Beforea;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.MockitoAnnotations;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(FooServiceImpl.class)
public class FooServiceImpTest {

    @InjectMocks
    private FooServiceImpl service;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        mockStatic(System.class);  // Powermock can mock static and private methods

        when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1");
        when(System.getenv("FOO_VAR_2")).thenReturn("test-foo-var-2");
        when(System.getenv("FOO_VAR_3")).thenReturn("test-foo-var-3");
    }

    @Test
    public void testSomeFooStuff() {        
        // Test
        service.doSomeFooStuff();

        verifyStatic();
        System.getenv("FOO_VAR_1");
        verifyStatic();
        System.getenv("FOO_VAR_2");
        verifyStatic();
        System.getenv("FOO_VAR_3");
    }
}
11
Mangusta

Découplez le code Java de la variable Environment, ce qui fournit un lecteur de variable plus abstrait que vous réalisez avec un EnvironmentVariableReader à partir de quel code lire ce test.

Ensuite, dans votre test, vous pouvez donner une implémentation différente du lecteur de variable qui fournit vos valeurs de test.

L'injection de dépendance peut aider à cela.

7
Andrea Colleoni

Cette réponse à la question Comment définir des variables d'environnement à partir de Java? permet de modifier la mappe (non modifiable) dans System.getenv (). Ainsi, bien que cela ne change pas VRAIMENT la valeur de la variable d’environnement du système d’exploitation, il peut être utilisé pour les tests unitaires, car il change ce que System.getenv retournera.

7
sudocode

Je pense que la façon la plus propre de faire cela est avec Mockito.spy (). C'est un peu plus léger que de créer une classe séparée à se moquer et à faire circuler.

Déplacez votre variable d’environnement vers une autre méthode:

@VisibleForTesting
String getEnvironmentVariable(String envVar) {
    return System.getenv(envVar);
}

Maintenant, dans votre test unitaire, faites ceci:

@Test
public void test() {
    ClassToTest classToTest = new ClassToTest();
    ClassToTest classToTestSpy = Mockito.spy(classToTest);
    Mockito.when(classToTestSpy.getEnvironmentVariable("key")).thenReturn("value");
    // Now test the method that uses getEnvironmentVariable
    assertEquals("changedvalue", classToTestSpy.methodToTest());
}
5
pgkelley

J'espère que le problème est résolu. J'ai juste pensé à dire ma solution.

Map<String, String> env = System.getenv();
    new MockUp<System>() {
        @Mock           
        public String getenv(String name) 
        {
            if (name.equalsIgnoreCase( "OUR_OWN_VARIABLE" )) {
                return "true";
            }
            return env.get(name);
        }
    };
3
Muthu