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.
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.
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 ().
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:
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 .
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");
}
}
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.
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.
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());
}
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);
}
};