Come testare il codice dipendente dalle variabili di ambiente usando JUnit?

Ho un pezzo di codice Java che utilizza una variabile di ambiente e il comportamento del codice dipende dal valore di questa variabile. Vorrei testare questo codice con diversi valori della variabile di ambiente. Come posso farlo in JUnit?

Ho visto alcuni modi per impostare le variabili di ambiente in Java in generale, ma sono più interessato al suo aspetto unitario, specialmente considerando che i test non devono interferire tra loro.

La solita soluzione è quella di creare una class che gestisca l’accesso a questa variabile ambientale, che è quindi ansible prendere in giro nella class di 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 class sotto test ottiene quindi la variabile di ambiente usando la class Environment, non direttamente da System.getenv ().

La libreria Regole di sistema fornisce una regola JUnit per l’impostazione delle variabili di ambiente.

 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: sono l’autore di System Rules.

Scollega il codice Java dalla variabile Ambiente fornendo un lettore di variabili più astratto che ti rendi conto con un EnvironmentVariableReader del tuo codice per testare le letture.

Quindi nel tuo test puoi dare un’implementazione diversa del lettore di variabili che fornisce i valori del test.

Iniezione di dipendenza può aiutare in questo.

In una situazione simile come questa in cui dovevo scrivere Test Case che dipende dalla Variabile d’Ambiente , ho provato a seguire:

  1. Ho scelto le regole del sistema come suggerito da Stefan Birkner . Il suo uso era semplice. Ma prima di allora, ho trovato il comportamento irregolare. In una corsa, funziona, nella prossima esecuzione fallisce. Ho studiato e ho scoperto che le regole di sistema funzionano bene con JUnit 4 o versione successiva. Ma nei miei casi, stavo usando alcuni barattoli che dipendevano da JUnit 3 . Quindi ho saltato le regole del sistema . Più su di esso puoi trovare qui l’annotazione @Rule non funziona mentre usi TestSuite in JUnit .
  2. Successivamente ho provato a creare la variabile di ambiente tramite la class Process Builder fornita da Java . Qui attraverso il codice Java possiamo creare una variabile d’ambiente, ma è necessario conoscere il nome del processo o del programma che non ho. Inoltre crea una variabile di ambiente per il processo figlio, non per il processo principale.

Ho sprecato un giorno usando i due precedenti metodi, ma inutilmente. Poi Maven è venuto in mio soccorso. Possiamo impostare le variabili d’ambiente o le proprietà di sistema tramite il file Maven POM , che ritengo sia il modo migliore per eseguire il test delle unità per il progetto basato su Maven . Di seguito è la voce che ho fatto nel file POM .

     org.apache.maven.plugins maven-surefire-plugin   PropertyValue1 PropertyValue2   EnvironmentVariableValue1 EnvironmentVariableValue2      

Dopo questo cambiamento, ho eseguito nuovamente Test case e improvvisamente tutto ha funzionato come previsto. Per le informazioni del lettore, ho esplorato questo approccio in Maven 3.x , quindi non ho idea di Maven 2.x.

Questa risposta alla domanda Come imposto le variabili d’ambiente da Java? fornisce un modo per modificare la mappa (non modificabile) in System.getenv (). Pertanto, anche se non modifica DAVVERO il valore della variabile di ambiente del SO, può essere utilizzato per il test delle unità poiché cambia ciò che System.getenv restituirà.

Non penso che questo sia già stato menzionato, ma potresti anche usare Powermockito :

Dato:

 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 } } 

Potresti fare quanto segue:

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

Penso che il modo più pulito per farlo sia con Mockito.spy (). È un po ‘più leggero rispetto alla creazione di una class separata per deridere e passare in giro.

Sposta la tua variabile di ambiente recuperando in un altro metodo:

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

Ora nel tuo test unitario fai questo:

 @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()); } 

Bene, puoi usare il metodo setup () per dichiarare i diversi valori del tuo ambiente. variabili in costanti. Quindi utilizzare queste costanti nei metodi di test utilizzati per testare il diverso scenario.

Io uso System.getEnv () per ottenere la mappa e la tengo come un campo, così posso prendermi in giro:

 public class AAA { Map environmentVars; public String readEnvironmentVar(String varName) { if (environmentVars==null) environmentVars = System.getenv(); return environmentVars.get(varName); } } public class AAATest { @Test public void test() { aaa.environmentVars = new HashMap(); aaa.environmentVars.put("NAME", "value"); assertEquals("value",aaa.readEnvironmentVar("NAME")); } } 

Se vuoi recuperare informazioni sulla variabile d’ambiente in Java, puoi chiamare il metodo: System.getenv(); . Come proprietà, questo metodo restituisce una mappa contenente i nomi delle variabili come chiavi e i valori delle variabili come valori della mappa. Ecco un esempio:

  import java.util.Map; public class EnvMap { public static void main (String[] args) { Map env = System.getenv(); for (String envName : env.keySet()) { System.out.format("%s=%s%n", envName, env.get(envName)); } } } 

Anche il metodo getEnv() può prendere una discussione. Per esempio :

 String myvalue = System.getEnv("MY_VARIABLE"); 

Per il test, vorrei fare qualcosa di simile a questo:

 public class Environment { public static String getVariable(String variable) { return System.getenv(variable); } @Test public class EnvVariableTest { @Test testVariable1(){ String value = Environment.getVariable("MY_VARIABLE1"); doSometest(value); } @Test testVariable2(){ String value2 = Environment.getVariable("MY_VARIABLE2"); doSometest(value); } }