블로그 번역

[23.12.19] 단위 테스트에서 환경 변수 Mocking

HOONY_612 2023. 12. 19. 18:35
반응형

소개

Unit Test 작성 업무 중 Enviroment Mocking에 대한 글을 읽었다.

자바는 환경 변수가 JVM 시작과 동시에 Immutable 하기 때문에 다른 언어에 비해서 Mocking이 어렵다.

해결하기 위해 최선의 방법은 로딩 될 때 환경변수를 로딩하는 것이지만 상황에 따라 환경 변수를 변경해야 할 때가 있다.

 

방법1: Pioneer

이 방법은 리플렉션 기반의 동작이기 때문에 JDK 17부터 사용 불가능하다.

만약 사용하고 싶다면 maven 옵션을 추가해주자.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <configuration>
        <argLine>
            --add-opens java.base/java.util=ALL-UNNAMED
            --add-opens java.base/java.lang=ALL-UNNAMED
        </argLine>
    </configuration>
</plugin>

 

의존성 추가

<dependency>
    <groupId>org.junit-pioneer</groupId>
    <artifactId>junit-pioneer</artifactId>
    <version>2.1.0</version>
    <scope>test</scope>
</dependency>

어노테이션 기반 작성

여러 개를 사용하고 싶다면 어노테이션을 여러 개 사용하자.

@SetEnvironmentVariable(key = "pioneer", value = "is pioneering")
class EnvironmentVariablesSetByJUnitPioneerUnitTest {

    @Test
    void variableCanBeRead() {
        assertThat(System.getenv("pioneer")).isEqualTo("is pioneering");
    }

}

환경 변수 지우기도 가능하다.

@ClearEnvironmentVariable(key = "pioneer")
@Test
void givenEnvironmentVariableIsClear_thenItIsNotSet() {
    assertThat(System.getenv("pioneer")).isNull();
}

 

방법2: System Stub

의존성 추가

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-jupiter</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

 

코드 작성

Extension의 역할은 환경변수 Clear 및 수정이다.

@ExtendWith(SystemStubsExtension.class)
public class TestClass {

    @SystemStub
    private EnvironmentVariables environment = new EnvironmentVariables("MY VARIABLE", "is set");

    @Test
    void givenEnvironmentVariableHasBeenSet_thenCanReadIt() {
        environment.set("MY VARIABLE", "clear");
        assertThat(System.getenv("MY VARIABLE")).isEqualTo("clear");
    }
}

 

방법3: System Stub Without a Test Framework

의존성 추가

<dependency>
    <groupId>uk.org.webcompere</groupId>
    <artifactId>system-stubs-core</artifactId>
    <version>2.1.3</version>
    <scope>test</scope>
</dependency>

람다 내부에서 사용가능

import static org.assertj.core.api.Assertions.assertThat;
import static uk.org.webcompere.systemstubs.SystemStubs.withEnvironmentVariables;

public class TestClass {

    @Test
    void useEnvironmentVariables() throws Exception {
        withEnvironmentVariables("system stubs", "in test")
                .execute(() -> {
                    assertThat(System.getenv("system stubs"))
                            .isEqualTo("in test");
                });
    }
}

 

나머지 방안

여러 방안들이 Example로 나와있다. 필요한 것에 맞게 선택해서 사용해보자.

 

Enviroment Mocking 피해야 하는 이유

 

 

아래와 같은 이유들로 환경 변수를 Mocking하는것은 올바르지 않다.

테스트가 순차적으로 실행된다는 보장은 없다.

동시성에 영향이 갈 수 있다.

따라서 Runtime에 Enviroment를 편집하는 건 매우 위험 할 수 있다. 

스프링 부트 같은 경우는 환경 변수를 대체할 수 있는 system properties를 정의하여 사용하자.

 

참고: https://www.baeldung.com/java-unit-testing-environment-variables#2-clearing-an-environment-variable

반응형