Как проверить код, зависящий от переменных среды с помощью JUnit?
У меня есть фрагмент кода Java, который использует переменную окружения, и поведение кода зависит от значения этой переменной. Я хотел бы проверить этот код с разными значениями переменной среды. Как я могу сделать это в JUnit?
Я видел некоторые способы установки переменных среды в Java В общем, но меня больше интересует аспект модульного тестирования, особенно учитывая, что тесты не должны мешать друг другу.
10 ответов:
обычным решением является создание класса, который управляет доступом к этой переменной среды, которую затем можно издеваться в тестовом классе.
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()); } }
тестируемый класс затем получает переменную среды, используя класс среды, а не непосредственно из системы.getenv ().
библиотека Системные Правила предоставляет правило JUnit для установки переменных среды.
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")); } }
отказ от ответственности: я автор правил системы.
отделите код Java от переменной среды, предоставляющей более абстрактное средство чтения переменных, которое вы реализуете с помощью EnvironmentVariableReader, из которого ваш код для тестирования считывается.
затем в тесте вы можете дать другую реализацию переменной reader, которая предоставляет ваши тестовые значения.
инъекция зависимостей может помочь в этом.
в подобной ситуации как это, где я должен был написать Тест зависит от Переменные Среды, я попробовал следующее:
- пошел к Системные Правила как было предложено Стефан Birkner. Его использование было простым. Но рано или поздно, я обнаружил, что поведение неустойчиво. В одном запуске он работает, в следующем запуске он терпит неудачу. Я исследовал и обнаружил, что системные правила хорошо работают с JUnit 4 или выше версия. но в моих случаях, я использовал некоторые банки, которые зависели от JUnit 3. Так что я пропустил Системные Правила. Подробнее об этом вы можете узнать здесь @rule аннотация не работает при использовании TestSuite в JUnit.
- далее я попытался создать Переменные Среды через Process Builder на основе. Ниже приведена запись, которую я сделал в пом.
<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>
после этого изменения, я побежала Тесты снова и вдруг все сработало как ожидалось. Для информации читателя, я исследовал этот подход в Maven 3.x, Так что я понятия не имею о Maven 2.x.
ответ на вопрос Как установить переменные среды из Java? предоставляет способ изменить (немодифицируемую) карту в системе.getenv (). Поэтому, хотя он действительно не изменяет значение переменной среды ОС, его можно использовать для модульного тестирования, поскольку он изменяет то, что
Я не думаю, что это уже упоминалось, но вы также можете использовать Powermockito:
дано:
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 } }
вы можете сделать следующее:
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"); } }
Я думаю, что самый чистый способ сделать это с Mockito.шпион.)( Это немного легче, чем создание отдельного класса, чтобы издеваться и передавать.
переместите выборку переменной среды в другой метод:
@VisibleForTesting String getEnvironmentVariable(String envVar) { return System.getenv(envVar); }
теперь в вашем модульном тесте сделайте это:
@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()); }
Ну вы можете использовать setup() метод для объявления различных значений вашего env. переменные в константы. Затем используйте эти константы в методах тестов, используемых для проверки другого сценария.
Я использую системы.getEnv() чтобы получить карту, и я держу ее как поле, поэтому я могу издеваться над ней:
public class AAA { Map<String, String> 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<String,String>(); aaa.environmentVars.put("NAME", "value"); assertEquals("value",aaa.readEnvironmentVar("NAME")); } }
если вы хотите получить информацию о переменной окружения в Java, вы можете вызвать метод :
System.getenv();
. В качестве свойств этот метод возвращает карту, содержащую имена переменных в качестве ключей и значения переменных в качестве значений карты. Вот пример :import java.util.Map; public class EnvMap { public static void main (String[] args) { Map<String, String> env = System.getenv(); for (String envName : env.keySet()) { System.out.format("%s=%s%n", envName, env.get(envName)); } } }
метод
getEnv()
can также принимает аргумент. Например :String myvalue = System.getEnv("MY_VARIABLE");
для тестирования я бы сделал что-то вроде этого :
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); } }