2017-10-06 81 views
14

假设我有一个使用Maven 3和junit的Java项目。有src/main/javasrc/test/java目录分别包含主要来源和测试来源,(一切都是标准的)。Java 9 + maven + junit:测试代码是否需要它自己的module-info.java以及它放在哪里?

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

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

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

主模块(in 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等)?

+0

先忘记Maven 2 ...使用Maven 3 + ...测试中的'module-info'是否从我的角度来看没有意义?背后的特殊要求/成就? – khmarbaise

+0

这是Maven 3,当然是 –

回答

4

该模块系统不之间的生产代码和测试代码区分,因此,如果选择模块化测试代码,所述prod.moduletest.module不能共享相同的包com.acme.project,如在specs描述:

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

如由Alan贝特曼指示的,编译的Maven插件使用在src /测试/ JAVA树编译代码时,使得受测试的模块与测试类增强由模块系统提供--patch-module and other options。在运行测试类时,Surefire插件也会执行此操作(请参阅Support running unit tests in named Java 9 modules)。这意味着您不需要将测试代码放入模块中。

+1

更改要测试的软件包有一个缺点,即您的测试不会再达到默认和受保护的修改器。 –

+1

该模块提供了--patch-module和其他选项来支持编译和执行与被测模块位于同一个封装/模块中的测试。在编译src/test树中的代码时,maven-compiler-plugin使用这些选项。对于surefire插件同上。 –

+0

@AlanBateman感谢这个信息。我不知道Maven是否这样做。我会用你的信息更新答案。 – manouti

7

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

应该只有一个单一的module-info.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 
} 

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

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

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

您可以通过使用指令处理 junitcompile-time dependency如下 -

requires static junit; 

使用Maven,你可以做到这一点遵循上述的结构和使用maven-surefire-plugin达到类似的效果,其将负责将测试修补到模块本身。

+0

我建议不要在目录结构中使用模块名称,因为它没有优势....? – khmarbaise

+0

@khmarbaise我相信你的意思是'com.acme.project/com/acme/project'。只需按照[快速入门指南](http://openjdk.java.net/projects/jigsaw/quick-start)即可。虽然我同意,但它没有提供任何优势。 – nullpointer

+1

在模块描述符中需要'junit'对我来说看起来不太好 – ZhekaKozlov

1

添加一些细节。

从9开始,Java文件(或带有类的目录)可以放在类路径上(如前所述),也可以放在模块路径上。如果它被添加到类路径中,它的模块信息被忽略,并且没有模块相关的限制(什么读什么,什么输出什么等)被应用。但是,如果将jar添加到模块路径中,则会将其视为模块,因此会处理其module-info,并会执行其他与模块相关的限制。

目前(版本2.20.1),maven-surefire-plugin只能以旧的方式工作,所以它将被测试的类放在classpath中,并且module-path被忽略。所以,现在,向Maven项目添加模块信息不应该改变任何使用Maven运行的测试(使用surefire插件)。

以我的情况下,命令行是这样的:

/bin/sh -c cd /home/rpuch/git/my/test-java9-modules-junit && /home/rpuch/soft/jdk-9/bin/java --add-modules java.se.ee -jar /home/rpuch/git/my/test-java9-modules-junit/target/surefire/surefirebooter852849097737067355.jar /home/rpuch/git/my/test-java9-modules-junit/target/surefire 2017-10-12T23-09-21_577-jvmRun1 surefire8407763413259855828tmp surefire_05575863484264768860tmp 

被测类不添加作为模块,所以它们的类路径上。

目前,https://issues.apache.org/jira/browse/SUREFIRE-1262(SUREFIRE-1420标记为SUREFIRE-1262的副本)正在进行工作,以教授Surefire插件将代码置于模块路径上进行测试。当它完成并发布时,将考虑模块信息。但是如果他们让被测模块自动读取junit模块(就像SUREFIRE-1420所建议的那样),module-info(这是一个主要的模块描述符)将不必包含对junit的引用(只有在测试时才需要) 。

简历:

  1. 模块的信息只需要被添加到主要来源
  2. 为是的时候,神火忽略新的模块相关的逻辑(但是这将在未来被改变)
  3. (当模块将在万无一失的测试工作) junit的可能不需要添加到模块,信息
  4. (当模块将在万无一失的测试工作)如果某些模块是测试所需的(并且只有它们),它可以按照@nullpointer的建议作为仅编译依赖(使用require static)添加。在这种情况下,Maven模块将不得不依赖于使用编译(而不是测试)范围提供该仅测试模块的工件,而我并不太喜欢这个工具。
相关问题