Java模块:Mockito 2.20.0的可访问性问题
我正在从Java 8迁移到Java 10,并且我正在运行我的测试,该测试现在由于包保护类而失败。构建在Maven 3.5.4+Oracle JDK 10.0.2下运行:
- MAVEN-COMPILER-PLUGIN 3.7.0+ASM 6.2
- maven-surefire-plugin 2.22.0+ASM 6.2+junit 5.2.0
- 编译器/Surefire都需要ASM 6.2,因为这些插件使用的ASM版本存在错误。
- moockito-core 2.20.0(但之前在Java 8中使用2.20.0)。
- 日食光子R
该项目可以在这里找到ide-bugs.zip(它位于Eclipse论坛,因为我为另一个问题Topic on Eclipse制作了这个Topic on Eclipse,这一次是因为Eclipse的模块有本地错误)。
测试非常简单:我们尝试用不同的访问级别模拟不同的类--所有这些都在Java 8中工作。
- 包保护类
- 公共类,但未导出,未打开
- 公共类未导出,但向Mockito开放
- 公共类未导出,但向所有人开放
- 包保护类未导出,但对Mockito打开
- 包保护类未导出,但向所有人开放
在Java 8中,情况1、5和6是相同的(包的访问受保护)。案例2、3和4相同(公共访问权限)。
测试失败,因为Mockito既不能:
- 类org.mockito.codegen.NotExportedOpenToMockitoProtected$MockitoMock$117073031无法访问其超类nodatafound.mjpmsuc.withopens.NotExportedOpenToMockitoProtected
- 类org.mockito.codegen.NotExportedNotOpenedPublic$MockitoMock$365628885(在未命名模块@0x3f07b12c中)无法访问类nodatafound.mjpmsuc.internal.NotExportedNotOpenedPublic(在模块nodatafound.moockito_jpms_usecase中),因为模块nodatafound.moockito_jpms_usecase不会将nodatafound.mjpmsu.Internal导出到未命名模块@0x3f07b12c
Mockito实际上有一个自动模块名,但被视为未命名模块,因为所有JAR都在类路径中找到一个大的"未命名模块"。
虽然我可以从包保护包迁移到非导出包,但我无法理解如何解决使我的接口/类对其他模块不可见的问题?
[编辑]一个月后更新了插件/依赖项的版本,但没有结果。
解决方案
我在这里找到了问题的部分答案:https://blog.codefx.org/java/java-module-system-tutorial/#Open-Packages-And-Modules
- Mockito正在使用反射从模块或类路径访问类。
- Mockito位于"未命名模块"中,因为Maven将其添加到类路径中,而不是模块路径中。这解释了为什么
opens package to org.mockito
从不工作:没有org.mockito
模块。 - Maven Surefire不会为了允许Mockito访问它而参与模块的"打开"。
- Mockito是(不再是?)能够模拟非私有类和非最终类。无论如何,包保护类都是私有的。错误相当明显:Mockito创建了一个扩展包保护类的类,现在失败了(它以前还在工作,但这可能是因为Mockito在与被模仿的包相同的包中创建了类)。
然而,这在每个模块的pom.xml
中提供了一个有问题的配置:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
--add-opens nodatafound.mockito_jpms_usecase/nodatafound.mjpmsuc=ALL-UNNAMED
</configuration>
</plugin>
我们需要显式将打开添加到未命名的模块。这不应在MODULE-INFO.Java中完成,因为它会将模块公开给所有其他模块或JAR,这不利于封装。
这有问题,因为:
- 您需要在pom.xml中为每个包指定它。
- 这会给surefire配置增加额外的负担,而我更喜欢简单的配置。
- 您没有来自IDE的验证;Eclipse将验证模块-info.java,标记为无效的包。
- M2E未将必要的
<argLine />
传递给Eclipse JUnit插件,导致在Eclipse中测试失败。
maven方法(据我所知在Eclipse中也是如此,可能在Gradle中也是如此)不允许为测试添加额外的模块信息;例如:让测试依赖是模块化的(这可能是使用每个源模块的专用测试模块来完成的,就像Eclipse对插件测试所做的那样)。
相关文章