返回

Java 11 PowerMockito 报错:如何解决?

java

如何解决 Java 11 中 PowerMockito 2 测试出现的 "javax.xml.parsers.FactoryFinder cannot access class jdk.xml.internal.SecuritySupport" 错误

在 Java 11 环境下使用 PowerMockito 2 运行测试时,你可能会遇到 "javax.xml.parsers.FactoryFinder cannot access class jdk.xml.internal.SecuritySupport" 这样的错误信息。这个错误提示表明,你的测试代码在尝试访问 jdk.xml.internal.SecuritySupport 类时遇到了权限问题。Java 9 引入了模块化系统 (JPMS),jdk.xml.internal 模块默认情况下不对未命名模块开放,这就导致了访问限制。

你可能首先会想到使用 @PowerMockIgnore({"com.sun.org.apache.xerces.*", "javax.xml.*", "org.xml.*", "javax.management.*"}) 注解来绕过这个问题。然而,这种方法并不理想,因为它会忽略对多个包的模拟,可能会降低测试覆盖率,甚至隐藏潜在的问题。

为了帮助你彻底解决这个问题,本文将介绍几种无需使用 @PowerMockIgnore 注解的解决方案。

解决方案一:升级 PowerMock 版本

PowerMock 在较新版本中已经解决了 Java 11 的兼容性问题。尝试将你的 PowerMock 依赖升级到最新版本:

testImplementation 'org.powermock:powermock-api-mockito2:2.0.14' // 使用最新版本
testImplementation "org.powermock:powermock-module-junit4:2.0.14" // 使用最新版本

升级后,重新运行你的测试,看看错误是否消失。

解决方案二:使用 --add-opens 参数

--add-opens JVM 参数允许你在运行时打开特定模块的包,使其对其他模块可见。 你可以通过在测试执行时添加以下 JVM 参数来解决这个问题:

--add-opens java.xml/jdk.xml.internal=ALL-UNNAMED

这个参数将 java.xml 模块中的 jdk.xml.internal 包开放给所有未命名模块。

你可以在 build.gradle 文件中配置测试任务的 JVM 参数,像这样:

tasks.test {
    jvmArgs '--add-opens', 'java.xml/jdk.xml.internal=ALL-UNNAMED'
}

解决方案三:将测试代码模块化

将你的测试代码模块化可以更精细地控制模块之间的依赖关系。创建一个 module-info.java 文件,并在其中声明你的测试模块需要依赖 java.xml 模块:

module com.example.myproject.test {
    requires java.xml;
}

虽然这种方法需要你对 Java 模块化系统有一定的了解,但它提供了更好的代码隔离和可维护性。

常见问题解答

1. 为什么要避免使用 @PowerMockIgnore 注解?

@PowerMockIgnore 注解会忽略对指定包的模拟,这可能会导致测试覆盖率降低,甚至隐藏潜在的问题。

2. 升级 PowerMock 版本后,问题仍然存在,我该怎么办?

确认你使用的 PowerMock 版本确实是最新的,并检查你的项目配置是否正确。

3. --add-opens 参数如何工作?

--add-opens 参数是 Java 9 引入的一个 JVM 参数,它允许你在运行时打开特定模块的包,使其对其他模块可见。

4. 什么是 Java 模块化系统 (JPMS)?

JPMS 是 Java 9 引入的一项重要功能,它允许你将代码组织成模块,并明确指定模块之间的依赖关系。

5. 我应该选择哪种解决方案?

建议优先考虑升级 PowerMock 版本或使用 --add-opens 参数,因为它们更易于实现。如果你的项目已经采用了模块化结构,那么将测试代码模块化也是一个不错的选择。