Java模块:Mockito 2.20.0的可访问性问题

2022-04-02 00:00:00 mockito java java-module maven-3 java-10

我正在从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中工作。

  1. 包保护类
  2. 公共类,但未导出,未打开
  3. 公共类未导出,但向Mockito开放
  4. 公共类未导出,但向所有人开放
  5. 包保护类未导出,但对Mockito打开
  6. 包保护类未导出,但向所有人开放

在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对插件测试所做的那样)。

相关文章