Как проверить код в зависимости от переменных среды с помощью JUnit?

У меня есть кусок кода Java, который использует переменную среды, а поведение кода зависит от значения этой переменной. Я хотел бы протестировать этот код с разными значениями переменной среды. Как я могу сделать это в JUnit?

Я видел несколько способов установить переменные среды в Java в целом, но меня больше интересует его модульный аспект, особенно учитывая, что тесты должны 't мешают друг другу.

Ответ 1

Обычным решением является создание класса, который управляет доступом к этой переменной окружения, которую вы можете затем высмеять в своем тестовом классе.

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

Затем тестируемый класс получает переменную среды, используя класс среды, а не непосредственно из System.getenv().

Ответ 2

Библиотека Системные правила предоставляет правило JUnit для установки переменных среды.

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

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

Отказ от ответственности: я являюсь автором системных правил.

Ответ 3

Отмените Java-код из переменной среды, предоставляя более абстрактное считывающее устройство с переменными, которое вы реализуете с помощью EnvironmentVariableReader, чтобы ваш код проверял чтение.

Затем в вашем тесте вы можете дать другую реализацию считывателя переменных, которая предоставляет ваши тестовые значения.

В этом может помочь инъекция зависимостей.

Ответ 4

Этот ответ на вопрос Как установить переменные среды из Java? дает возможность изменить (немодифицируемая) Карта в System.getenv(). Таким образом, хотя он не ДЕЙСТВИТЕЛЬНО изменяет значение переменной среды ОС, его можно использовать для модульного тестирования, поскольку он меняет то, что System.getenv вернется.

Ответ 5

Я не думаю, что это уже упоминалось, но вы также можете использовать 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");
    }
}

Ответ 6

В подобной ситуации, когда мне приходилось писать Test Case, которая зависит от Переменная среды, я пробовал следующее:

  • Я пошел на Системные правила, как предложил Стефан Биркнер. Его использование было простым. Но раньше, чем позже, я обнаружил, что поведение неустойчиво. За один проход он работает, в самом начале он терпит неудачу. Я исследовал и обнаружил, что системные правила хорошо работают с версией JUnit 4 или более поздней версии.. Но в моих случаях я использовал некоторые Jars, зависящие от JUnit 3. Поэтому я пропустил Системные правила. Подробнее об этом вы можете найти здесь Аннотации @Rule не работают при использовании TestSuite в JUnit.
  • Далее я попытался создать переменную среды через класс Process Builder, предоставляемый Java. Здесь, используя Java-код, мы можем создать переменную среды, но вам нужно знать имя процесс или , которого я не сделал. Также он создает переменную среды для дочернего процесса, а не для основного процесса.

Я потратил день, используя два вышеупомянутых подхода, но безрезультатно. Тогда мне помог Maven. Мы можем установить Переменные среды или Свойства системы через файл Maven POM, который, по моему мнению, лучший способ сделать Тестирование единицы измерения для Maven. Ниже приведена запись, сделанная в файле 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>

После этого изменения я снова запустил Test Cases, и внезапно все сработало, как ожидалось. Для информации читателя я изучил этот подход в Maven 3.x, поэтому я понятия не имею о Maven 2.x.

Ответ 7

Я думаю, что самый чистый способ сделать это - с помощью Mockito.spy(). Это немного более легкий, чем создание отдельного класса для издевки и прохождения.

Перемещение выбранной переменной среды в другой метод:

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

Теперь в вашем unit test сделайте следующее:

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

Ответ 8

Хорошо, вы можете использовать метод setup() для объявления разных значений вашего env. переменные в константах. Затем используйте эти константы в методах тестирования, используемых для тестирования различного сценария.

Ответ 9

Если вы хотите получить информацию о переменной окружения в 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() также может принимать аргумент. Например:

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