MavenとJavaを使用したマルチモジュールプロジェクトがあります。 Java 9/10/11に移行してモジュールを実装しようとしています JSR 376:Java Platform Module System)のように =、JPMS)。プロジェクトはすでにMavenモジュールで構成されており、依存関係は単純であったため、プロジェクトのモジュール記述子の作成は非常に簡単でした。
各Mavenモジュールの独自のモジュール記述子(module-info.Java
)がsrc/main/Java
フォルダーに追加されました。テストクラスのモジュール記述子はありません。
しかし、解決できなかった問題に遭遇し、解決方法の説明が見つかりませんでした。
モジュール間test MavenおよびJavaモジュール?との依存関係をどうやって持つことができますか?
私の場合、「共通」のMavenモジュールがあり、これにはいくつかのインターフェースおよび/または抽象クラスが含まれています(ただし、具体的な実装はありません)。同じMavenモジュールで、これらのインターフェース/抽象クラスの実装の適切な動作を確認するabstractテストがあります。次に、1つ以上のサブモジュールがあり、インターフェース/抽象クラスの実装と抽象テストを拡張するテストがあります。
ただし、Mavenビルドのtest
フェーズを実行しようとすると、サブモジュールは次のエラーで失敗します:
[ERROR] Failed to execute goal org.Apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project my-impl-module: Compilation failure: Compilation failure:
[ERROR] C:\projects\com.example\my-module-test\my-impl-module\src\test\Java\com\example\impl\FooImplTest.Java:[4,25] error: cannot find symbol
[ERROR] symbol: class FooAbstractTest
[ERROR] location: package com.example.common
テストはモジュールの一部ではないが原因であると考えられます。また、Mavenがモジュールのスコープ内でテストを実行するために何らかの「魔法」をかけても、(何らかの理由で)私が依存しているモジュールのテストでは機能しません。どうすれば修正できますか?
プロジェクトの構造は次のようになります( ここで利用可能な完全なデモプロジェクトファイル ):
├───my-common-module
│ ├───pom.xml
│ └───src
│ ├───main
│ │ └───Java
│ │ ├───com
│ │ │ └───example
│ │ │ └───common
│ │ │ ├───AbstractFoo.Java (abstract, implements Foo)
│ │ │ └───Foo.Java (interface)
│ │ └───module-info.Java (my.common.module: exports com.example.common)
│ └───test
│ └───Java
│ └───com
│ └───example
│ └───common
│ └───FooAbstractTest.Java (abstract class, tests Foo)
├───my-impl-module
│ ├───pom.xml
│ └───src
│ ├───main
│ │ └───Java
│ │ ├───com
│ │ │ └───example
│ │ │ └───impl
│ │ │ └───FooImpl.Java (extends AbstractFoo)
│ │ └───module-info.Java (my.impl.module: requires my.common.module)
│ └───test
│ └───Java
│ └───com
│ └───example
│ └───impl
│ └───FooImplTest.Java (extends FooAbstractTest)
└───pom.xml
my-impl-module/pom.xml
の依存関係は次のとおりです。
<dependencies>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-common-module</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.example</groupId>
<artifactId>my-common-module</artifactId>
<classifier>tests</classifier> <!-- tried type:test-jar instead, same error -->
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
注:上記は、問題を実証するために作成したプロジェクトです。実際のプロジェクトははるかに複雑で、 ここにあります (マスターブランチはnotモジュール化されています)ですが、原理は同じです。
PS:すべてが通常のクラスパスを使用してコンパイルおよび実行されるため(つまり、IntelliJ、またはJavaモジュール記述子なしのMaven)、すべてがコンパイルおよび実行されるため、コード自体に問題はないと思います。問題Javaモジュールとモジュールパスで紹介されています。
あなたのデモプロジェクトに基づいて、私はあなたのエラーを複製することができました。とはいえ、プロジェクトをビルドできるようにするために、最初に失敗した後のrevised変更は次のとおりです。
すべてのモジュールにmaven-compiler-plugin
バージョン3.8.0を追加しました。 Mavenでモジュールをコンパイルするには、3.7以降のバージョンが必要です。少なくとも、これはNetBeansが示した警告です。害はないので、commonとimplementationモジュールの両方のPOMファイルにプラグインを追加しました。
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
<id>compile</id>
</execution>
</executions>
</plugin>
テストクラスを独自のjar
ファイルにエクスポートしたので、実装モジュールなどの誰でも利用できるようになります。そのためには、my-common-module/pom.xml
ファイルに以下を追加する必要があります。
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>test-jar</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
これにより、my-common-module
テストクラスが-tests.jar
ファイルにエクスポートされます(例:my-common-module-1.0-SNAPSHOT-tests.jar
)。この post に示されているように、通常のjar
ファイルの実行を追加する必要がないことに注意してください。ただし、これにより、次に対処するエラーが発生します。
実装テストクラスをコンパイルするときにテストクラスがロードされるように、テストパッケージの名前をmy-common-module
からcom.example.common.test
に変更します。これにより、最初のjar
、この場合はモジュールがロードされ、2番目のjar
、テストjarファイルは無視されます。興味深いことに、観察に基づいて、Mavenコンパイルパラメーターがクラスパスの最初にtests.jar
が指定されていることを示しているため、モジュールパスの方がクラスパスよりも優先順位が高いと結論付けています。 mvn clean validate test -X
を実行すると、コンパイルパラメータが表示されます。
-d /home/testenv/NetBeansProjects/MavenProject/Implementation/target/test-classes -classpath /home/testenv/NetBeansProjects/MavenProject/Implementation/target/test-classes:/home/testenv/.m2/repository/com/example/Declaration/1.0-SNAPSHOT/Declaration-1.0-SNAPSHOT-tests.jar:/home/testenv/.m2/repository/junit/junit/4.12/junit-4.12.jar:/home/testenv/.m2/repository/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar: --module-path /home/testenv/NetBeansProjects/MavenProject/Implementation/target/classes:/home/testenv/.m2/repository/com/example/Declaration/1.0-SNAPSHOT/Declaration-1.0-SNAPSHOT.jar: -sourcepath /home/testenv/NetBeansProjects/MavenProject/Implementation/src/test/Java:/home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations: -s /home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations -g -nowarn -target 11 -source 11 -encoding UTF-8 --patch-module example.implementation=/home/testenv/NetBeansProjects/MavenProject/Implementation/target/classes:/home/testenv/NetBeansProjects/MavenProject/Implementation/src/test/Java:/home/testenv/NetBeansProjects/MavenProject/Implementation/target/generated-test-sources/test-annotations: --add-reads example.implementation=ALL-UNNAMED
エクスポートされたテストクラスを実装モジュールで利用できるようにする必要があります。この依存関係をmy-impl-module/pom.xml
に追加します。
<dependency>
<groupId>com.example</groupId>
<artifactId>Declaration</artifactId>
<version>1.0-SNAPSHOT</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
最後にmy-impl-module
テストクラスで、インポートを更新して新しいテストパッケージcom.example.common.text
を指定し、my-common-module
テストクラスにアクセスします。
import com.example.declaration.test.AbstractFooTest;
import com.example.declaration.Foo;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test class inheriting from common module...
*/
public class FooImplementationTest extends AbstractFooTest { ... }
新しい変更のmvn clean package
のテスト結果は次のとおりです。
Java-cross-module-testing GitHubリポジトリのサンプルコードを更新しました。私が唯一残している質問は、あなたもそうだと思いますが、実装モジュールをモジュールではなく通常のjar
プロジェクトとして定義したときに、なぜうまくいったのかです。しかし、それは、別の日に遊んでみます。うまくいけば、私が提供したものがあなたの問題を解決します。
私はまったく同じようにしようとしましたが、ホワイトボックステストとモジュールテストの依存関係の両方を持つことは不可能ですプロジェクトの構造を使用して行う:
1 /ホワイトボックステストの問題は、JPMSがMavenとは異なりテストVSメインの概念を持たないため、モジュールパッチで機能することです。したがって、これはテスト依存関係で動作しない、またはテスト依存関係でモジュール情報を汚染する必要があるなどの問題を引き起こします。
2 /では、ホワイトボックステストを続けないでください。ただし、ブラックボックステストのmaven構造を使用して、つまり、各モジュールXをXとXテストに分割します。 Xのみにmodule-info.Javaがあり、テストはクラスパスで実行されるため、これらの問題はすべてスキップします。
私が考えることができる唯一の欠点は(重要度が高い順に)です:
ちなみに(それがあなたがやっていることなら)、モジュール化する価値はないと思います。スプリング自体はまだモジュール化されていないので、スプリングブートアプリはコストを支払いますが、いくつかの利点を享受します(ただし、別の話であるlibを作成している場合)。
ここで例を見つけることができます:
a /例を取得:
git clone https://github.com/vandekeiser/ddd-metamodel.git
git checkout stackoverflow
b /例を見てください: