Java 9 + Maven + JUnit:测试代码是否需要自己的module-info.java以及放在哪里?


问题内容

假设我有一个使用Maven
3和junit的Java项目。有src/main/javasrc/test/java目录分别包含主要来源和测试来源(所有内容都是标准的)。

现在,我想将项目迁移到Java9。src/main/java内容表示Java 9模块。有com/acme/project/module- info.java看大约是这样的:

module com.acme.project {
    require module1;
    require module2;
    ...
}

如果测试代码module- info.java本身需要怎么办?例如,添加对某些模块的依赖关系,该依赖关系仅用于测试,而对于生产代码则不需要。在这种情况下,我必须把module- info.javasrc/test/java/com/acme/project/给模块不同的名称。这样,Maven似乎将主源和测试源视为不同的模块,因此我必须将包从主模块导出到测试模块,并在测试模块中需要包,如下所示:

主模块(在中src/main/java/com/acme/project):

module prod.module {
    exports com.acme.project to test.module;
}

测试模块(中src/test/java/com/acme/project):

module test.module {
    requires junit;
    requires prod.module;
}

这产生

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:testCompile (default-testCompile) on project test-java9-modules-junit: Compilation failure: Compilation failure:
[ERROR] /home/rpuch/git/my/test-java9-modules-junit/src/test/java/com/acme/project/GreeterTest.java:[1,1] package exists in another module: prod.module

因为一个包在两个模块中定义。所以现在我必须在主模块和测试模块中有不同的项目,这不方便。

我觉得我走错了路,这一切看起来都很丑陋。如何module- info.java在测试代​​码中拥有自己的功能,或者require没有它如何实现相同的效果(,等)?


问题答案:

模块系统无法区分生产代码和测试代码,因此,如果您选择模块化测试代码,则prod.moduletest.module不能共享相同的包com.acme.project,如规格中所述:

互不干扰
-Java编译器,虚拟机和运行时系统必须确保包含相同名称的程序包的模块不会相互干扰。如果两个不同的模块包含相同名称的程序包,则从每个模块的角度来看,该程序包中的所有类型和成员都仅由该模块定义。一个模块中该程序包中的代码必须不能访问另一模块中该程序包中的程序包专用类型或成员。

正如艾伦·贝特曼(Alan Bateman)所指出的那样,当在src / test / java树中编译代码时,Maven编译器插件使用--patch-
module和
模块系统提供的其他选项,以便使用测试类扩展被测模块。而且,在运行测试类时,Surefire插件也可以完成此操作(请参阅“
支持在命名的Java
9模块中运行单元测试”
)。这意味着您无需将测试代码放在模块中。