환경 변수를 사용하는 Java 코드가 있으며 코드의 동작은이 변수의 값에 따라 다릅니다. 환경 변수의 다른 값 으로이 코드를 테스트하고 싶습니다. JUnit에서 어떻게 할 수 있습니까?
일반적으로 Java 에서 환경 변수를 설정하는 몇 가지 방법을 보았지만 특히 테스트가 서로 방해하지 않아야한다는 점을 고려하여 단위 테스트 측면에 더 관심이 있습니다.
환경 변수를 사용하는 Java 코드가 있으며 코드의 동작은이 변수의 값에 따라 다릅니다. 환경 변수의 다른 값 으로이 코드를 테스트하고 싶습니다. JUnit에서 어떻게 할 수 있습니까?
일반적으로 Java 에서 환경 변수를 설정하는 몇 가지 방법을 보았지만 특히 테스트가 서로 방해하지 않아야한다는 점을 고려하여 단위 테스트 측면에 더 관심이 있습니다.
답변:
라이브러리 시스템 규칙 은 환경 변수 설정을위한 JUnit 규칙을 제공합니다.
import org.junit.contrib.java.lang.system.EnvironmentVariables;
public class EnvironmentVariablesTest {
@Rule
public final EnvironmentVariables environmentVariables
= new EnvironmentVariables();
@Test
public void setEnvironmentVariable() {
environmentVariables.set("name", "value");
assertEquals("value", System.getenv("name"));
}
}
면책 조항 : 저는 시스템 규칙의 저자입니다.
import org.junit.contrib.java.lang.system.EnvironmentVariables;
com.github.stefanbirkner:system-rules
프로젝트에 종속성을 추가해야합니다 . MavenCentral에서 사용할 수 있습니다.
일반적인 솔루션은이 환경 변수에 대한 액세스를 관리하는 클래스를 작성하여 테스트 클래스에서 모의 할 수 있습니다.
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 ()에서 직접이 아니라 Environment 클래스를 사용하여 환경 변수를 가져옵니다.
Environment Variable에 의존하는 Test Case 를 작성 해야하는 이와 비슷한 상황에서 다음을 시도했습니다.
위의 두 가지 접근법을 사용하여 하루를 낭비했지만 아무 소용이 없습니다. 그런 다음 Maven 이 구조했습니다. Maven 기반 프로젝트에 대한 단위 테스트 를 수행하는 가장 좋은 방법은 Maven POM 파일을 통해 환경 변수 또는 시스템 속성 을 설정할 수 있습니다 . 아래는 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>
이 변경 후, 나는 테스트 케이스를 다시 실행 했고 갑자기 모든 것이 예상대로 작동했습니다. 독자 정보를 위해 Maven 3.x 에서이 접근법을 탐색 했으므로 Maven 2.x 에 대해서는 전혀 모릅니다 .
가장 깨끗한 방법은 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());
}
나는 이것이 아직 언급되지 않았다고 생각하지만 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");
}
}
when(System.getenv("FOO_VAR_1")).thenReturn("test-foo-var-1")
원인이 org.mockito.exceptions.misusing.MissingMethodInvocationException: when() requires an argument which has to be 'a method call on a mock'.
오류
Java 변수를 환경 변수에서 분리하면 코드를 읽을 환경 코드를 EnvironmentVariableReader로 인식 할 수있는보다 추상적 인 변수 리더가 제공됩니다.
그런 다음 테스트에서 테스트 값을 제공하는 변수 판독기의 다른 구현을 제공 할 수 있습니다.
의존성 주입이 도움이 될 수 있습니다.
이 질문 에 대한 답변 은 Java에서 환경 변수를 어떻게 설정합니까? System.getenv ()에서 (수정 불가능한) 맵을 변경하는 방법을 제공합니다. 따라서 OS 환경 변수의 값을 실제로 변경하지는 않지만 System.getenv 가 반환 할 내용을 변경하므로 단위 테스트에 사용할 수 있습니다 .
문제가 해결되기를 바랍니다. 방금 해결책을 말하려고 생각했습니다.
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);
}
};
이 답변 이 Maven 프로젝트에 가장 적합 하다고 생각하더라도 반영을 통해 달성 할 수 있습니다 ( Java 8 에서 테스트 ).
public class TestClass {
private static final Map<String, String> DEFAULTS = new HashMap<>(System.getenv());
private static Map<String, String> envMap;
@Test
public void aTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "155");
assertEquals("155", System.getenv("NUMBER_OF_PROCESSORS"));
}
@Test
public void anotherTest() {
assertEquals("6", System.getenv("NUMBER_OF_PROCESSORS"));
System.getenv().put("NUMBER_OF_PROCESSORS", "77");
assertEquals("77", System.getenv("NUMBER_OF_PROCESSORS"));
}
/*
* Restore default variables for each test
*/
@BeforeEach
public void initEnvMap() {
envMap.clear();
envMap.putAll(DEFAULTS);
}
@BeforeAll
public static void accessFields() throws Exception {
envMap = new HashMap<>();
Class<?> clazz = Class.forName("java.lang.ProcessEnvironment");
Field theCaseInsensitiveEnvironmentField = clazz.getDeclaredField("theCaseInsensitiveEnvironment");
Field theUnmodifiableEnvironmentField = clazz.getDeclaredField("theUnmodifiableEnvironment");
removeStaticFinalAndSetValue(theCaseInsensitiveEnvironmentField, envMap);
removeStaticFinalAndSetValue(theUnmodifiableEnvironmentField, envMap);
}
private static void removeStaticFinalAndSetValue(Field field, Object value) throws Exception {
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
field.set(null, value);
}
}
theCaseInsensitiveEnvironment
필드 가 없고 대신 필드가 있습니다 theEnvironment
.```envMap = new HashMap <> (); 클래스 <?> clazz = Class.forName ( "java.lang.ProcessEnvironment"); Field theEnvironmentField = clazz.getDeclaredField ( "theEnvironment"); UnmodifiableEnvironmentField 필드 = clazz.getDeclaredField ( "theUnmodifiableEnvironment"); removeStaticFinalAndSetValue (EnvironmentField, envMap); removeStaticFinalAndSetValue (수정 불가능한 환경 필드, envMap); ```
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);
}
}
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"));
}
}