Как проверить код, зависящий от переменных среды, используя JUnit? - PullRequest
96 голосов
/ 17 ноября 2011

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

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

Ответы [ 11 ]

136 голосов
/ 14 февраля 2016

Библиотека Системные правила предоставляет правило 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"));
  }
}

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

61 голосов
/ 17 ноября 2011

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

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 ().

14 голосов
/ 16 июня 2017

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

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

Я потратил впустую день, используя два вышеупомянутых подхода, но безрезультатно.Затем Maven пришел ко мне на помощь.Мы можем установить Переменные среды или Системные свойства * от 1040 * до 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 .

12 голосов
/ 28 июня 2017

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

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

7 голосов
/ 17 ноября 2011

Отсоедините код Java от переменной Environment, предоставляя более абстрактное средство чтения переменных, которое вы реализуете с EnvironmentVariableReader, код которого вы проверяете на чтение.

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

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

5 голосов
/ 24 июня 2015

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

Переместите выборку переменной окружения в другой метод:

@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());
}
3 голосов
/ 22 ноября 2018

Надеюсь, что проблема решена. Я просто подумал, чтобы сказать свое решение.

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);
        }
    };
0 голосов
/ 07 сентября 2018

Я использую System.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"));
         }
}
0 голосов
/ 17 ноября 2011

Если вы хотите получить информацию о переменной среды в 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); 
     }   
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...