You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Java 17与JUnit5环境下Mock System.getenv()?

如何在Java和JUnit环境下Mock环境变量(解决system-rules库的反射访问异常)

问题描述

我尝试用system-rules库Mock System.getenv(),实现代码如下:

@ExtendWith(MockitoExtension.class)
public class SampleTest {
   @Rule
   public final EnvironmentVariables environmentVariables = new EnvironmentVariables();
   @BeforeEach
   public void setup() {
       environmentVariables.set("AWS_REGION", TEST_REGION.toString());
       environmentVariables.set("CLIENT_ACCOUNT_ROLE", ROLE_ARN);
   }
   ...
}

但构建失败,抛出异常:

java.lang.reflect.InaccessibleObjectException: Unable to make field private final java.util.Map java.util.Collections$UnmodifiableMap.m accessible: module java.base does not "opens java.util" to unnamed module

异常触发于environmentVariables.set("AWS_REGION", TEST_REGION.toString());行。

可行解决方案

方案1:使用JUnit Pioneer的EnvironmentVariableExtension

JUnit Pioneer提供的EnvironmentVariableExtension是适配JUnit 5和Java模块系统的环境变量Mock工具,不会触发反射权限问题。

修改测试代码如下:

@ExtendWith({MockitoExtension.class, EnvironmentVariableExtension.class})
public class SampleTest {

    @BeforeEach
    void setup(@EnvironmentVariableSource Map<String, String> envVars) {
        envVars.put("AWS_REGION", TEST_REGION.toString());
        envVars.put("CLIENT_ACCOUNT_ROLE", ROLE_ARN);
    }

    // 也可以直接用注解快速设置
    @Test
    @SetEnvironmentVariable(key = "AWS_REGION", value = "us-east-1")
    @SetEnvironmentVariable(key = "CLIENT_ACCOUNT_ROLE", value = "arn:aws:iam::123456789012:role/test-role")
    void testWithEnvVars() {
        // 测试逻辑
    }
}

需要在项目中引入JUnit Pioneer依赖(以Maven为例):

<dependency>
    <groupId>org.junit-pioneer</groupId>
    <artifactId>junit-pioneer</artifactId>
    <version>2.0.1</version> <!-- 替换为最新稳定版 -->
    <scope>test</scope>
</dependency>

方案2:封装环境变量获取逻辑(推荐)

避免直接调用System.getenv(),封装一个工具类统一处理环境变量获取,测试时Mock这个工具类即可绕过系统限制。

  1. 封装环境变量工具类:
public class EnvUtils {
    public static String getEnv(String key) {
        return System.getenv(key);
    }
}
  1. 业务代码中使用该工具类:
public class AwsClient {
    public String getRegion() {
        return EnvUtils.getEnv("AWS_REGION");
    }
}
  1. 测试中Mock工具类(借助Mockito):
@ExtendWith(MockitoExtension.class)
public class SampleTest {

    @MockStatic(EnvUtils.class)
    void setupMocks() {
        Mockito.when(EnvUtils.getEnv("AWS_REGION")).thenReturn(TEST_REGION.toString());
        Mockito.when(EnvUtils.getEnv("CLIENT_ACCOUNT_ROLE")).thenReturn(ROLE_ARN);
    }

    @Test
    void testEnvDependentLogic() {
        // 测试逻辑,EnvUtils的调用会返回预设的Mock值
    }
}

方案3:临时添加VM参数(应急方案)

如果必须继续使用system-rules库,可以在测试启动时添加VM参数开放反射权限:

--add-opens java.base/java.util=ALL-UNNAMED

该方法会破坏Java模块系统的封装性,仅适合临时应急,不推荐长期使用。

内容的提问来源于stack exchange,提问作者MarkBeras

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 11:32:59