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

如何让JUnit5与JDK10(Jigsaw)及Maven3协同工作?

解决JDK10模块化项目中JUnit5测试的InaccessibleObjectException问题

这个InaccessibleObjectException的根源很清晰:你的主代码模块de.truncated.framework.shared只通过exports对外暴露了de.truncated.framework.shared.resources包,但JUnit5需要通过反射实例化你的测试类,而反射访问需要模块显式opens包给调用方——这里你的测试代码属于「未命名模块(unnamed module)」,所以模块系统拒绝了反射访问。JDK10移除--permit-illegal-access是模块化规范的必然,我们需要用合规的方式解决。

下面是三种不同场景下的解决方案,按推荐程度排序:

方案1:修改主模块的module-info.java,opens测试包给未命名模块(最直接)

JUnit需要反射创建ResourceManagerTest实例,你只需在主模块的module-info.java中,把测试类所在的包opens给未命名模块即可:

module de.truncated.framework.shared {
    // 保留原有的exports语句,保证正常编译/运行访问
    exports de.truncated.framework.shared.resources;
    
    // 添加这行,允许未命名模块反射访问该包
    opens de.truncated.framework.shared.resources to ALL-UNNAMED;
}

如果想更严谨,也可以只开放给JUnit的核心模块(比如org.junit.jupiter.engine、org.junit.platform.commons),但测试阶段用ALL-UNNAMED足够简洁高效。

方案2:将测试代码模块化(最规范的模块化实践)

如果你的项目想完全遵循Jigsaw模块化规范,可以给测试代码创建独立的模块:

  1. 在src/test/java下创建测试模块的module-info.java:
module de.truncated.framework.shared.test {
    // 依赖主业务模块
    requires de.truncated.framework.shared;
    // 依赖JUnit5核心模块
    requires org.junit.jupiter.api;
    requires org.junit.jupiter.engine;
    
    // 声明测试类所在包开放给JUnit引擎(因为需要反射实例化)
    opens de.truncated.framework.shared.resources to org.junit.jupiter.engine;
}
  1. 调整主模块的module-info.java,只开放给测试模块(更安全):
module de.truncated.framework.shared {
    exports de.truncated.framework.shared.resources;
    // 仅向测试模块开放反射权限
    opens de.truncated.framework.shared.resources to de.truncated.framework.shared.test;
}

这种方式能严格控制模块间的访问权限,适合大型模块化项目长期维护。

方案3:通过Maven Surefire插件添加JVM参数(无需修改模块代码)

如果你不想修改模块定义,可以在Maven Surefire插件中添加--add-opens参数,临时让主模块开放包给未命名模块:
修改你的maven-surefire-plugin配置,添加<argLine>节点:

<plugin>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>${surefire.version}</version>
    <configuration>
        <!-- 新增JVM参数,强制开放包给未命名模块 -->
        <argLine>--add-opens de.truncated.framework.shared/de.truncated.framework.shared.resources=ALL-UNNAMED</argLine>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-surefire-provider</artifactId>
            <version>${junit.platform.version}</version>
        </dependency>
        <dependency>
            <groupId>org.ow2.asm</groupId>
            <artifactId>asm</artifactId>
            <version>${asm.version}</version>
        </dependency>
    </dependencies>
</plugin>

这个参数仅在测试运行时生效,适合快速验证或临时场景。

额外注意事项

  • 你的Maven Surefire版本(2.21.0)对JDK10模块化的支持足够,但如果后续遇到其他兼容性问题,可以尝试升级到3.0.0-M7及以上版本,对JUnit5和模块化的适配更完善。
  • 确保maven-compiler-plugin已经正确启用模块化编译——你当前配置的source和target为10,这已经满足要求,3.7.0版本会自动处理模块路径。

内容的提问来源于stack exchange,提问作者Jan S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:47:41