简体   繁体   English

我如何打开包并要求依赖于仅用于 JUnit 测试的测试范围模块

[英]How do I open packages and require dependencies on test scope modules only for JUnit testing

I'm migrating a jar project from java 10 using classpath to java 11 using the java 9 jigsaw modules.我正在使用 java 9 jigsaw 模块将一个 jar 项目从使用 classpath 的 java 10 迁移到 java 11。 There are JUnit5 tests for the project.该项目有 JUnit5 测试。 The test dependencies are provided at test scope by maven.测试依赖项由 maven 在测试范围内提供。 How to make all packages open for testing but not open when the module is used by another project?当模块被另一个项目使用时,如何打开所有包进行测试但不打开?

The jar project is just providing a few classes (like a utility project) for other projects (so no main class needed). jar 项目只是为其他项目提供了一些类(如实用程序项目)(因此不需要主类)。

The project got 5 packages at /src/main/java/a/b/c/ .该项目在/src/main/java/a/b/c/获得了 5 个包。 2 of them should be accessible for projects using this jar.使用这个 jar 的项目应该可以访问其中的 2 个。 The other 3 are for internal use only (used by the accessible ones).其他 3 个仅供内部使用(由可访问的使用)。 The tests are located at /src/test/java/a/b/c/ .测试位于/src/test/java/a/b/c/ These tests have dependencies (JUnit, mockito, junt-params) provided in test scope, since the tests are not relevant for the projects using this jar这些测试具有在测试范围内提供的依赖项(JUnit、mockito、junt-params),因为这些测试与使用此 jar 的项目无关

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

I have provided a module-info.java at /src/main/java/ :我在/src/main/java/提供了一个module-info.java

module moduleName {

requires java.base;

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

so now the public classes in package 1 and 3 should be accessible to other projects as expected (I have not been able to verify this yet).所以现在包 1 和 3 中的公共类应该可以按预期被其他项目访问(我还没有能够验证这一点)。

Running the Tests now results in java.lang.reflect.InaccessibleObjectException: Unable to make abcpackage1.collections.SomeTest() accessible: module moduleName does not "opens abcpackage1" to unnamed module @6a84a97d现在运行测试会导致 java.lang.reflect.InaccessibleObjectException:无法使 abcpackage1.collections.SomeTest() 可访问:模块 moduleName 不会“打开 abcpackage1”到未命名的模块 @6a84a97d

when I open the packages (with opens ) everything runs smooth.当我打开包(打开)时,一切运行顺利。 But now all packages are now opened.但是现在所有的包都被打开了。 I expect package 2, 4 and 5 to be only accessible while testing and 1 and 3 should not be open for reflection (so only exported).我希望包 2、4 和 5 只能在测试时访问,而 1 和 3 不应该为反射打开(因此只能导出)。

I came to think, since maven tells me unnamed module @6a84a97d , this might be a module created for testing.我开始想,既然 maven 告诉我未命名的模块@6a84a97d ,这可能是为测试而创建的模块。 That made me try adding a module-info.java at /src/test/java/ for testing.这让我尝试在/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;
}

now maven (3.5.4) states:现在 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

Technologies:技术:

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

As stated earlier I expect package 2, 4 and 5 to be only accessible while testing and the tests to be run on building the jar with maven.如前所述,我希望包 2、4 和 5 只能在测试时访问,并且在使用 maven 构建 jar 时运行测试。 Package 1 and 3 should be exported for use in other projects but not open for reflection (so only exported not opened).包 1 和包 3 应该导出用于其他项目,但不打开用于反射(因此仅导出未打开)。

If you need additional information don't hesitate to ask.如果您需要更多信息,请随时询问。

Thanks in Advance提前致谢

Kevin凯文

"Welcome to Testing In The Modular World", Kevin. “欢迎在模块化世界中进行测试”,凯文。

I compiled a blog about that topic here: https://github.com/sormuras/testing-in-the-modular-world我在这里编译了一篇关于该主题的博客: https : //github.com/sormuras/testing-in-the-modular-world

Basically, when it comes to white-box testing, you need to tweak the module system either at test compile or test runtime to allow testing frameworks to by-pass the module system barriers.基本上,当涉及到白盒测试时,您需要在测试编译测试运行时调整模块系统,以允许测试框架绕过模块系统障碍。

I guess, you're on the right track ... maybe Surefire does the wrong thing?我想,你在正确的轨道上......也许 Surefire 做错了事? Want to give https://github.com/sormuras/junit-platform-maven-plugin I wrote a shot?想给https://github.com/sormuras/junit-platform-maven-plugin写一个截图吗? This plugin supports black- and white-box testing out of the box.该插件支持开箱即用的黑白盒测试。 Especially, this plugin shines, when you provide a test/java/module-info.java test module descriptor.特别是,当您提供test/java/module-info.java测试模块描述符时,这个插件会发光。

See this "picture" for how to organize modular tests without touching the main module descriptor:有关如何在触及主模块描述符的情况下组织模块化测试的信息,请参见此“图片”:

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; }

This pattern should be easy to adopt to your setup as well.这种模式也应该很容易被你的设置采用。

Related question: How do you organize tests in a modular Java project?相关问题: 如何在模块化 Java 项目中组织测试?

The issue could have been solved if junit was packaged as java9 module.如果将 junit 打包为 java9 模块,则问题可能已经解决。 Than your error would change to something like比你的错误会变成类似的东西

"Unable to make abcpackage1.collections.SomeTest() accessible: module moduleName does not "opens abcpackage1" to junit5 module @6a84a97d “无法使 abcpackage1.collections.SomeTest() 可访问:模块 moduleName 不会“打开 abcpackage1”到junit5模块 @6a84a97d

In this case you could open it just to junit5 module (or any"named" test module which would be trying to use reflection on your classes).在这种情况下,您可以将它打开到junit5模块(或任何试图在您的类上使用反射的“命名”测试模块)。 Since currently I don't think this is the case (junit5 belongs to unnamed module from java perspective), your alternate options would be由于目前我认为情况并非如此(junit5 从 Java 的角度来看属于未命名模块),您的替代选择是

  1. move tests to separate maven module.将测试移动到单独的 maven 模块。 You would have two maven modules yourModule-1.0 and yourModule-tests-1.0 .您将有两个 Maven 模块yourModule-1.0yourModule-tests-1.0 yourModule-tests-1.0 would depend on yourModule-1.0 , so in maven it would build. yourModule-tests-1.0将取决于yourModule-1.0 ,因此在 maven 中它会构建。 Then you could open only your test module for reflection with open module moduleNameTest {} in your module-info.java .然后你可以只打开你的测试模块进行反射,在你的module-info.java使用open module moduleNameTest {} You main module would still be protected.您的主模块仍将受到保护。

  2. prefix package with tests with some "prefix-package", so instead abcpackage1.collections.SomeTest() you would have abcmytests.package1.collections.SomeTest() .带有一些“前缀包”的测试的前缀包,所以代替abcpackage1.collections.SomeTest()你会有abcmytests.package1.collections.SomeTest() Then when you open only your tests package abcmytests.package1.collections.SomeTest() for reflection while keeping your main source safe, as it remains in another package然后当你只打开你的测试包abcmytests.package1.collections.SomeTest()进行反射,同时保持你的主源安全,因为它保留在另一个包中

  3. you can live with that for now and simply open your package with opens abcpackage1.collections.SomeTest() .您现在可以接受它,只需使用opens abcpackage1.collections.SomeTest()打开您的包。 Unless you work on some shared library, noone ever would probably want to use reflection on your code.除非你在某个共享库上工作,否则没有人可能想在你的代码上使用反射。

  4. Following on assumption from point 3. the easiest is to open the whole module for reflection, by declaring it as open module moduleName {} instead of just ' module moduleName {} .根据第 3 点的假设,最简单的方法是打开整个模块进行反射,将其声明为open module moduleName {}而不是 ' module moduleName {} This way you don't need to adjust your module-info.java each time you create test in not-yet-open package.这样,您每次在尚未打开的包中创建测试时都不需要调整module-info.java

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM