【问题标题】:How do I open packages and require dependencies on test scope modules only for JUnit testing如何打开包并要求仅用于 JUnit 测试的测试范围模块的依赖项
【发布时间】:2019-01-07 05:48:22
【问题描述】:

我正在将一个 jar 项目从使用类路径的 java 10 迁移到使用 java 9 jigsaw 模块的 java 11。 该项目有 JUnit5 测试。 测试依赖项由 maven 在测试范围内提供。 模块被其他项目使用时,如何让所有包都打开测试但不打开?

jar 项目只是为其他项目提供了一些类(如实用程序项目)(因此不需要主类)。

该项目在 /src/main/java/a/b/c/ 获得了 5 个包。 使用此 jar 的项目应该可以访问其中的 2 个。 其他 3 个仅供内部使用(由可访问的使用)。 测试位于 /src/test/java/a/b/c/。 这些测试在测试范围内提供了依赖项(JUnit、mockito、junt-params),因为这些测试与使用此 jar 的项目无关

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

我在 /src/main/java/ 提供了一个 module-info.java

module moduleName {

requires java.base;

exports a.b.c.package1;
exports a.b.c.package3;
}

所以现在包 1 和 3 中的公共类应该可以按预期被其他项目访问(我还无法验证这一点)。

现在运行测试会导致 java.lang.reflect.InaccessibleObjectException: Unable to make a.b.c.package1.collections.SomeTest() 可访问:模块 moduleName 不会“打开 a.b.c.package1”到未命名的模块 @6a84a97d

当我打开包(使用 opens)时,一切运行顺利。 但是现在所有的包都打开了。 我希望包 2、4 和 5 只能在测试时访问,并且 1 和 3 不应该为反射打开(所以只能导出)。

我开始想,既然 maven 告诉我未命名的模块 @6a84a97d,这可能是为测试而创建的模块。 这让我尝试在 /src/test/java/ 添加一个 module-info.java 进行测试。

module moduleNameTest {
requires moduleName; // the code to test
requires java.base;  // java.base could be transient on moduleName

// test dependencies
requires org.junit.jupiter.api;
requires org.junit.jupiter.params;
}

现在 maven (3.5.4) 状态:

src/test/java/module-info.java:[3,20] module not found: moduleName
src/test/java/module-info.java:[4,31] module not found: org.junit.jupiter.api
src/test/java/module-info.java:[5,31] module not found: org.junit.jupiter.params

技术:

  • java openJDK 11
  • MVN 3.5.4
  • JUnit 5.3.0
  • Surefire 插件 3.0.0-M3
  • 模拟 2.21.0

如前所述,我希望包 2、4 和 5 只能在测试时访问,并且在使用 maven 构建 jar 时运行测试。包 1 和 3 应该导出用于其他项目,但不打开反射(所以只导出不打开)。

如果您需要更多信息,请随时询问。

提前致谢

凯文

【问题讨论】:

    标签: java maven junit5 java-platform-module-system


    【解决方案1】:

    “欢迎来到模块化世界进行测试”,Kevin。

    我在这里编写了一篇关于该主题的博客:https://github.com/sormuras/testing-in-the-modular-world

    基本上,当涉及到白盒测试时,您需要在 test compiletest runtime 调整模块系统以允许绕过测试框架模块系统障碍。

    我猜,你是在正确的轨道上......也许 Surefire 做错了事?想给https://github.com/sormuras/junit-platform-maven-plugin我写了一个镜头?该插件支持开箱即用的黑盒和白盒测试。特别是,当您提供 test/java/module-info.java 测试模块描述符时,此插件会大放异彩。

    查看这张“图片”了解如何在不接触主模块描述符的情况下组织模块化测试

    src ├── main │ └── java │ ├── foo │ │ ├── PackageFoo.java │ │ └── PublicFoo.java │ └── module-info.java <------------------ module foo { exports foo; } ├── test │ └── java .--- open module foo { │ ├── foo / exports foo; │ │ └── PackageFooTests.java / requires org.junit.jupiter.api; │ └── module-info.[java|test] <----< } └── it \ └── bar °---- --add-reads └── src foo=org.junit.jupiter.api └── test --add-opens └── java foo/foo=org.junit.platform.commons ├── bar │ └── PublicFooTests.java └── module-info.java <------ open module bar { requires foo; requires org.junit.jupiter.api; }

    这种模式也应该很容易在您的设置中采用。

    相关问题:How do you organize tests in a modular Java project?

    【讨论】:

    • 嗨@Somuras,感谢您的回复。似乎我必须在每个包之前加上 --add-opens 和 --add-reads 而不是说 --add-opens package1 package2 package3 ... 在弄清楚它是否有效之后。顺便说一句,是否有可能在 mvn 输出中突出显示测试结果(就像在 java 8 中一样),其中 [INFO] [ 223 测试成功 ] 中的 223 以绿色突出显示,失败的测试以红色突出显示?
    • 不客气。请在此处打开有关着色的问题:github.com/sormuras/junit-platform-maven-plugin 提前致谢。
    • 我遇到了与问题中描述的完全相同的问题。但是,答案对我没有帮助。如果我将module-info.java 也放入src/test/java 中,则会收到文件重复的错误,因为它已经存在于src/main/java 中。如果我改为添加module-info.test,则不会发生任何事情。该文件被完全忽略。即使我把绝对的无用语和语法错误放在那里,它也没有任何效果。那么建议的解决方案是否过时了?
    • @Jörg 我将 sormuras 的 junit-platform-maven-plugin 添加到 pom 文件中的构建中,并将 module-info.test 放入 test/resources(如 github.com/sormuras/testing-in-the-modular-world/blob/master/… 中所做的那样)文件包含信息、jvm 参数、需要 (add-reads) 和打开 (add-opens) 的模块希望这有帮助
    • 和 topickstarter 有同样的问题。当我添加 test/java/module-info.java 时,IDEA 向我显示错误“模块中已存在'module-info.java'”。我做错了什么?
    【解决方案2】:

    如果将 junit 打包为 java9 模块,问题可能已经解决。比你的错误会变成类似

    “无法使 a.b.c.package1.collections.SomeTest() 可访问:模块模块名称不会“打开 a.b.c.package1”到 junit5 模块 @6a84a97d

    在这种情况下,您可以只打开 junit5 模块(或任何试图在您的类上使用反射的“命名”测试模块)。由于目前我认为情况并非如此(从 java 的角度来看,junit5 属于未命名模块),因此您的替代选项是

    1. 将测试移动到单独的 Maven 模块。您将拥有两个 maven 模块 yourModule-1.0yourModule-tests-1.0yourModule-tests-1.0 将取决于 yourModule-1.0,因此在 Maven 中它会构建。然后,您可以在module-info.java 中使用open module moduleNameTest {} 仅打开您的测试模块进行反射。您的主模块仍将受到保护。

    2. 带有一些“前缀包”的测试的前缀包,所以a.b.c.package1.collections.SomeTest() 你会得到a.b.c.mytests.package1.collections.SomeTest()。然后,当您只打开您的测试包 a.b.c.mytests.package1.collections.SomeTest() 进行反射时,同时保持您的主要源代码安全,因为它保留在另一个包中

    3. 你现在可以忍受它,只需使用opens a.b.c.package1.collections.SomeTest() 打开你的包。除非您在某个共享库上工作,否则可能没有人愿意对您的代码使用反射。

    4. 根据第 3 点的假设。最简单的方法是打开整个模块进行反射,将其声明为 open module moduleName {} 而不仅仅是 'module moduleName {}。这样你就不需要每次在尚未打开的包中创建测试时调整你的module-info.java

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-04
      • 2017-05-02
      • 1970-01-01
      • 2014-02-18
      • 2015-03-08
      相关资源
      最近更新 更多