Maven の Surefire プラグインと JMockit と JaCoCo プラグイン
ビルドツールとして Maven を使っている Java プロジェクトで JMockit と JaCoCo を使いたいときの話。 ユニットテストの実行には Maven Surefire プラグインを使用しているものとする。 また、JaCoCo の適用には JaCoCo Maven プラグインを使用するものとする。
JMockit と JaCoCo の -javaagent
指定を共存させる
JMockit も JaCoCo も、Java プログラミング言語エージェントの仕組みを利用している *1。 なので、どちらも基本的には -javaagent
の指定が必要である。
JMockit の -javaagent
指定
JMockit の方は、Surefire プラグインの argLine
パラメータで -javaagent
を指定する。
<plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.21.0</version> <!-- or some other version --> <configuration> <argLine> -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar </argLine> <!-- ... --> </configuration> <plugin> <!-- ... --> <plugins>JMockit - Tutorial - Introduction
JaCoCo の -javaagent
指定
JaCoCo については jacoco:prepare-agent
ゴールにて argLine
プロパティ *2 に -javaagent
が追加される仕組みになっている。
Surefire プラグインに argLine
パラメータが指定されていないときには argLine
プロパティの値が使われるので、Surefire プラグインに argLine
パラメータが指定されていない場合にはそれ以上の設定は必要ない。
一方で、Surefire プラグインに argLine
パラメータの指定がされている場合は (そのままでは) JaCoCo プラグインが設定した argLine
プロパティの値が使われないため、別途設定が必要となる。 具体的には、Surefire プラグインの late property evaluation (late replacement) を使用する。 これは、プロパティ参照の ${...}
の代わりに @{...}
を使うというもの。 ${...}
を使った場合はプラグインの実行前に評価されるため JaCoCo プラグインが argLine
プロパティを変更してもそれが反映されないが、@{...}
を使うとプラグインの実行後の値が反映される。
One of the ways to do this in case of maven-surefire-plugin - is to use syntax for late property evaluation:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <argLine>@{argLine} -your -extra -arguments</argLine> </configuration> </plugin>
IntelliJ IDEA での問題
さて、Maven でビルドを実行する際に JMockit と JaCoCo を共存させるだけならここまでで解決するが、さらにややこしいのが IntelliJ IDEA の存在である。
IntelliJ IDEA で Maven プロジェクトを扱う場合、デフォルトでは JUnit 実行時に Surefire プラグインの argLine
パラメータを読み取るのだが、IntelliJ IDEA は late replacement (@{...}
) に対応していない。 そのため、下記のようなエラーが発生してしまう。
エラー: メイン・クラス@{argLine}が見つからなかったかロードできませんでした
- IntelliJ IDEA が
@{...}
を解釈しない件 : https://youtrack.jetbrains.com/issue/IDEA-143187
回避策の一つは、IntelliJ IDEA でのユニットテスト実行時に Surefire プラグインの argLine
パラメータを参照する設定を無効にすること。 設定の中の 「Maven」 の 「Running Tests」 で Surefire プラグインの argLine
を参照するかどうか指定できる。
私が採った回避策は、argLine
パラメータには空文字列として宣言したプロパティを含めておき、JaCoCo を有効にしたいときだけコマンドライン引数で @{argLine}
を埋め込むというもの。
<properties> <!-- Surefire プラグインの `argLine` に含める文字列。 JaCoCo の Java Agent を有効にするためには `@{argLine}` を指定すること。 IntelliJ IDEA が `@{...}` による late replacement に対応しておらず、直接 `@{argLine}` を指定すると IntelliJ IDEA でのテスト実行時にエラーが発生してしまうので、`@{argLine}` をコマンドラインオプションで指定できるように このようなプロパティを用意した。 See : http://maven.apache.org/surefire/maven-surefire-plugin/test-mojo.html (Surefire Plugin の `argLine` の説明) See : https://www.eclemma.org/jacoco/trunk/doc/prepare-agent-mojo.html (JaCoCo の Java Agent の指定について) See : https://youtrack.jetbrains.com/issue/IDEA-143187 (IntelliJ IDEA が argLine の `@{...}` を解釈しない件) --> <surefireArgLine/> </properties> <!-- (中略) --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.19.1</version> <configuration> <argLine> ${surefireArgLine} <!-- See : http://jmockit.github.io/tutorial/Introduction.html#runningTests --> -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar </argLine>
上のようにしておけば IntelliJ IDEA でのテスト実行にエラーが出ることはない。 そして Maven をコマンドラインから動かすときには、下記のように指定すれば JaCoCo が有効になる。
mvn package -D surefireArgLine="@{argLine}"
もっといい方法があれば知りたい……。
参考
- Java プログラミング言語エージェントについて : java.lang.instrument (Java SE 10 & JDK 10 )