Java 9 + maven + junit:测试代码是否需要模块信息.java以及将其放在哪里?

2022-08-31 17:04:09

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

现在我想将项目迁移到 Java 9。 内容表示 Java 9 模块;看起来大致是这样的:src/main/javacom/acme/project/module-info.java

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

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

主模块 (在 ):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.javarequire


答案 1

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

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

正如Alan Bateman所指出的,Maven编译器插件在src/test/java树中编译代码时使用模块系统提供的--patch-module和其他选项,以便使用测试类来增强被测模块。在运行测试类时,Surefire插件也可以完成此操作(请参阅支持在命名的Java 9模块中运行单元测试)。这意味着您不需要将测试代码放在模块中。


答案 2

您可能需要重新考虑要尝试实现的项目设计。由于您正在将模块及其测试实现到项目中,因此应避免为每个模块单独使用不同的模块。

对于模块及其相应的测试,应该只有一个模块信息.java

您的相关项目结构可能如下所示:-

Project/
|-- pom.xml/
|
|-- src/
|   |-- test/
|   |   |-- com.acme.project
|   |   |        |-- com/acme/project
|   |   |        |      |-- SomeTest.java
|   |   
|   |-- main/
|   |   |-- com.acme.project
|   |   |    |-- module-info.java
|   |   |    |-- com/acme/project
|   |   |    |    |-- Main.java

其中可能进一步是:-module-info.java

module com.acme.project {
    requires module1;
    requires module2;
    // requires junit; not required using Maven
}

只是为了按照您的问题总结上述所有内容 -

我觉得我走错了路,这一切开始看起来非常丑陋。如何在测试代码中拥有自己的模块信息.java,或者没有它我如何实现相同的效果(要求等)?

是的,您不应该考虑为测试代码管理不同的模块,使其变得复杂。

通过使用如下指令,您可以将 junit 视为编译时依赖项,从而实现类似的效果-

requires static junit;

使用Maven,您可以按照上述结构实现此目的,并使用它将负责将测试本身修补到模块中。maven-surefire-plugin


推荐