2017-10-06 83 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模塊將不得不依賴於使用編譯(而不是測試)範圍提供該僅測試模塊的工件,而我並不太喜歡這個工具。
相關問題