JUnit를 사용하여 환경변수에 따라 코드를 테스트하는 방법?
나는 환경변수를 사용하는 자바코드를 가지고 있는데, 코드의 동작은 이 변수의 값에 따라 달라진다.나는 환경변수의 다른 값으로 이 코드를 테스트하고 싶다.JUnit에서 어떻게 해?
일반적으로 자바에서 환경변수를 설정하는 몇 가지 방법을 보아 왔지만, 특히 시험이 서로 간섭하지 않아야 한다는 점을 고려할 때, 그 측면에 더 관심이 있다.
도서관 시스템 람다에는 방법이 있다.withEnvironmentVariables
환경 변수 설정용.
import static com.github.stefanbirkner.systemlambda.SystemLambda.*;
public void EnvironmentVariablesTest {
@Test
public void setEnvironmentVariable() {
String value = withEnvironmentVariable("name", "value")
.execute(() -> System.getenv("name"));
assertEquals("value", value);
}
}
Java 5 ~ 7의 경우, 라이브러리 시스템 규칙에는 JUnit 규칙이 있다.EnvironmentVariables
.
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"));
}
}
전체 공개:나는 두 도서관의 작가다.
일반적인 해결책은 이 환경변수에 대한 접근을 관리하는 클래스를 만드는 것이다. 그러면 당신은 당신의 시험 클래스에서 그것을 조롱할 수 있다.
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());
}
}
그런 다음 테스트 대상 클래스는 시스템에서 직접 가져오지 않고 환경 클래스를 사용하여 환경 변수를 얻는다.…을 경험하다.
환경변수에 의존하는 테스트 케이스를 작성해야 하는 이와 비슷한 상황에서 다음과 같이 노력했다.
- 나는 Stefan Birkner의 제안대로 시스템 규칙을 선택했다.그 용도는 간단했다.하지만 곧, 나는 그 행동이 불규칙하다는 것을 알았다.한 번 실행하면 효과가 있고, 바로 다음 실행에서는 실패한다.조사해보니 시스템 룰이 JUnit 4 이상 버전과 잘 어울린다.하지만 내 경우에는 JUnit 3에 의존하는 몇 개의 항아리를 사용하고 있었다.그래서 나는 시스템 규칙을 건너뛰었다.자세한 내용은 여기 @Rule 주석이 JUnit에서 TestSuite를 사용하는 동안 작동하지 않는다는 것을 참조하십시오.
- 다음으로 Java에서 제공하는 Process Builder 클래스를 통해 Environment Variable을 만들려고 했다.여기 자바코드를 통해 환경변수를 만들 수 있지만, 내가 하지 않은 프로세스나 프로그램 이름을 알아야 해.또한 주요 프로세스가 아닌 하위 프로세스에 대한 환경 변수를 생성한다.
위의 두 가지 방법을 사용하여 하루를 허비했지만 소용이 없었다.그때 메이븐이 나를 구하러 왔다.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>
이 변화 이후 나는 다시 테스트 케이스를 실행했고 갑자기 모든 것이 예상대로 작동했다.독자들의 정보를 위해 나는 메이븐 3.x에서 이 접근법을 탐구하였기 때문에 메이븐 2.x에 대해서는 전혀 알지 못한다.
이것을 하는 가장 깨끗한 방법은 모키토.스파이()와 함께 하는 것이라고 생각한다.조롱하고 전전하기 위해 따로 클래스를 만드는 것보다 조금 더 가볍다.
환경 변수 가져오기를 다른 메서드로 이동:
@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());
}
JUnit 4 사용자에게는 스테판 버크너가 제안한 시스템 람다(System Lambda)가 적합하다.
JUnit 5를 사용하는 경우 JUnit Pional 확장 팩이 있다.그것은 함께 나온다.@ClearEnvironmentVariable
그리고@SetEnvironmentVariable
. 문서에서:
그
@ClearEnvironmentVariable
그리고@SetEnvironmentVariable
주석을 사용하여 테스트 실행을 위한 환경 변수의 값을 각각 설정할 수 있다.두 주석 모두 시험 방법과 등급 수준에 따라 작용하며, 반복할 수 있을 뿐만 아니라 조합할 수도 있다.주석 처리된 방법을 실행한 후 주석에서 언급된 변수는 원래 값으로 복원되거나 이전에 주석을 사용하지 않았다면 삭제된다.시험 중 변경된 기타 환경변수는 복구되지 않는다.
예:
@Test
@ClearEnvironmentVariable(key = "SOME_VARIABLE")
@SetEnvironmentVariable(key = "ANOTHER_VARIABLE", value = "new value")
void test() {
assertNull(System.getenv("SOME_VARIABLE"));
assertEquals("new value", System.getenv("ANOTHER_VARIABLE"));
}
아직 언급되지 않은 것 같지만 파워모키토를 사용해도 된다.
주어진:
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");
}
}
읽기를 테스트할 코드를 EnvironmentVariableReader로 실현하는 보다 추상적인 변수 판독기를 제공하는 환경 변수와 Java 코드를 분리하십시오.
그런 다음 시험에서 당신은 당신의 시험 값을 제공하는 가변 판독기의 다른 구현을 제공할 수 있다.
의존성 주입은 이것을 도울 수 있다.
Java에서 환경 변수를 설정하는 방법은?라는 질문에 대한 이 답변은 (수정 불가능한) 시스템 맵을 변경할 수 있는 방법을 제공한다.…을 경험하다.따라서 OS 환경 변수의 값을 실제로 변경하지는 않지만, 시스템 변경에 따라 유닛 테스트에 사용할 수 있다.enven은 돌아올 것이다.
메이븐 프로젝트에서는 이 답이 가장 좋다고 생각하지만, 반성을 통해서도 얻을 수 있다(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);
}
}
이 문제가 해결되길 바란다.난 그냥 내 해결책을 말하려고 생각했어.
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);
}
};
전화를 조롱하는 데 파워모크를 사용할 수 있다.다음과 같은 경우:
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv("MyEnvVariable")).thenReturn("DesiredValue");
또한 다음과 같은 방법으로 모든 통화를 조롱할 수 있다.
PowerMockito.mockStatic(System.class);
PowerMockito.when(System.getenv(Mockito.anyString())).thenReturn(envVariable);
도서관 https://github.com/webcompere/system-stubs/tree/master/system-stubs-jupiter - 의 포크system-lambda
5 JUnit 5 플그dghinda 제공:
@ExtendWith(SystemStubsExtension.class)
class SomeTest {
@SystemStub
private EnvironmentVariables environmentVariables =
new EnvironmentVariables("name", "value");
@Test
void someTest() {
// environment is set here
// can set a new value into the environment too
environmentVariables.set("other", "value");
// tidy up happens at end of this test
}
}
https://junit-pioneer.org/ 대안은 컴파일 시 환경 변수 값을 알도록 요구한다.위의 내용은 또한 환경변수의 설정을 지원한다.@BeforeAll
, 즉 그것은 그것과 같은 것들과 잘 상호작용을 한다는 것을 의미한다.Testcontainers
아동 테스트에 필요한 자원을 마련할 수 있을 겁니다
변수를 전달하고, 설정하고, 삭제하는 등의 방법을 런타임에 개발하는 데 위의 제안들에 많은 초점이 맞춰져 있다.하지만 '구조적으로' 테스트하기 위해서, 여러분은 다른 시나리오에 대해 다른 테스트 세트를 갖고 싶어 하십니까?'중대한' 통합 테스트 빌드를 실행하고자 할 때와 거의 비슷하지만, 대부분의 경우 통합 테스트 빌드를 건너뛰고 싶을 때 입니다.하지만 '실시간 내에 물건을 설정하는 방법을 생각해내지 않고, 그냥 네가 원하는 것을 말해라'예전에는 사람들이 스프링부트를 통해 특정 테스트를 실행하자고 제안한다면, 예를 들어, 사람들이 스프링부트를 통해 특정 테스트를 실행하도록 지도하는 것이 많은 일이었습니다. 하지만 스프링부트 몬스터를 프로젝트에 끌어들이지 않았다면, 'JUnits만 실행하면' 끔찍한 발자국을 남기는 것 같죠, 그렇죠, 그렇죠?그렇지 않으면 다소 불편한 POM XML 저글링의 부하를 의미할 수도 있고, '90년대의 움직임'이라고 하자면 여전히 'XML로 봄콩'을 만들자고 고집하는 것만큼 불편할 수도 있고, 궁극적인 600라인 logback.xml을 뽐내거나 하는 것만큼 불편할 수도 있다.
요즘은 Junit 5를 그냥 사용할 수 있다(이 예는 maven에 대한 예시인데, 자세한 내용은 JUnit 5 User Guide 5에서 찾을 수 있다.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>5.7.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
그 다음에
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
그런 다음 즐겨찾는 유틸리티 lib에서 다음과 같은 간단한 주석 클래스를 만드십시오.
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@EnabledIfEnvironmentVariable(named = "MAVEN_CMD_LINE_ARGS", matches = "(.*)integration-testing(.*)")
public @interface IntegrationTest {}
따라서 cmdline 옵션이 예를 들어 -Pintegration-testing을 포함할 때마다 그리고 그때서야 @Integration이시험 주석으로 된 시험 등급/방법 화재.또는 특정 maven 프로필을 사용하지 않고(및 설정) 다음을 통해 '트리거' 시스템 속성을 전달하려는 경우
mvn <cmds> -DmySystemPop=mySystemPropValue
그리고 이를 트리거하도록 주석 인터페이스를 조정하십시오(예, @Enabled도 있음).ifSystemProperty).또는 당신의 껍질이 '필요한 모든 것'을 담도록 설정되었는지, 혹은 위에서 제시된 것처럼 실제로 당신의 POM XML을 통해 시스템 환경을 추가하는 '고통'을 겪었는지 확인한다.
당신의 코드가 런타임에 내부적으로 부러워하거나 조롱하는 환경을 만지작거리게 되면, 그것을 설정하고 실행 중에 스스로를 변화시키기 위해 런타임의 환경을 '지우는' 것은 나쁜, 어쩌면 심지어 위험한 접근처럼 보인다 - 누군가 항상 조만간 잠시 동안 눈치채지 못할 '숨겨진' 내부 실수를 저지르리라고 상상하는 것은 쉽다.o는 갑자기 일어나서 나중에 생산에 있어서 당신을 심하게 물게 된다.?일반적으로 '주어진 입력'이 '예상된 출력'을 제공한다는 접근법을 선호하는데, 이는 시간이 지남에 따라 쉽게 파악되고 유지될 수 있는 것이다. 동료 코더들은 '즉각'으로 볼 수 있을 것이다.
잘 '답답변'을 하거나, 어쩌면 이 접근법을 선호하는 이유에 대한 의견일 수도 있다(예, 처음에는 이 질문의 제목을 읽고, 즉 'JUnit을 사용하여 환경 변수에 따라 코드를 테스트하는 방법'을 답하기 위해 나아갔다).
모든 언어(그리고 심지어 언어 간에도)와 함께 모든 운영 체제에서 항상 작동하는 느리고 신뢰할 수 있는 구식 방법은 당신이 필요로 하는 "시스템/환경" 데이터를 임시 텍스트 파일에 쓰고 필요할 때 읽은 다음 그것을 지우는 것이다.물론 병렬로 실행하는 경우에는 파일의 고유한 이름이 필요하며, 중요한 정보를 입력하는 경우에는 암호화가 필요하다.
간단히
아래에 maven 종속성 추가
<!-- for JUnit 4 -->
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-junit4</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
<!-- for JUnit 5 -->
<dependency>
<groupId>uk.org.webcompere</groupId>
<artifactId>system-stubs-jupiter</artifactId>
<version>1.1.0</version>
<scope>test</scope>
</dependency>
시험 내에서도 비슷한 것을 사용할 수 있다.
@Rule
public EnvironmentVariablesRule environmentVariablesRule = new EnvironmentVariablesRule();
@Test
public void givenEnvironmentCanBeModified_whenSetEnvironment_thenItIsSet() {
// mock that the system contains an environment variable "ENV_VAR" having value "value1"
environmentVariablesRule.set("ENV_VAR", "value1");
assertThat(System.getenv("ENV_VAR")).isEqualTo("value1");
}
자세한 내용은 참조
https://https:///www.baeldung.com/java-system-stubs
설정() 방법을 사용하여 상수에 있는 변수의 다른 값을 선언할 수 있다.그런 다음 다른 시나리오를 테스트하는 데 사용되는 테스트 방법에 이 상수를 사용하십시오.
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()
또한 논쟁도 할 수 있다.를 들어:csv:
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"));
}
}
'programing' 카테고리의 다른 글
gets 기능이 왜 그렇게 위험해서 사용하면 안 되는가? (0) | 2022.05.08 |
---|---|
Vuejs + Vuex Get 확인란 상태(체크됨) (0) | 2022.05.08 |
오류: 알 수 없는 유형 이름 'bool' (0) | 2022.05.07 |
기본값을 방지한 다음 VueJ를 사용하여 기본값을 제출하는 방법s (0) | 2022.05.07 |
UPER-CASE에서 "정적 최종 로거"를 선언해야 하는가? (0) | 2022.05.07 |