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


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

Я видел некоторые способы установки переменных среды в Java В общем, но меня больше интересует аспект модульного тестирования, особенно учитывая, что тесты не должны мешать друг другу.

10 67

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, которая предоставляет ваши тестовые значения.

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

в подобной ситуации как это, где я должен был написать Тест зависит от Переменные Среды, я попробовал следующее:

  1. пошел к Системные Правила как было предложено Стефан Birkner. Его использование было простым. Но рано или поздно, я обнаружил, что поведение неустойчиво. В одном запуске он работает, в следующем запуске он терпит неудачу. Я исследовал и обнаружил, что системные правила хорошо работают с JUnit 4 или выше версия. но в моих случаях, я использовал некоторые банки, которые зависели от JUnit 3. Так что я пропустил Системные Правила. Подробнее об этом вы можете узнать здесь @rule аннотация не работает при использовании TestSuite в JUnit.
  2. далее я попытался создать Переменные Среды через 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); 
     }   
 }