続けるって難しい。2月は2本しか書いてないしな。
えっと、前回のエントリでは、Maven+Jetty+Seleniumで総合テストを行うための構成を簡単に紹介しました。今回は、JaCoCoでカバレッジ計測を行い、テストレポートを出力するところまでを紹介します。
※Spring Boot+Maven+Selenium+JaCoCoも可能です。詳細はこちらのエントリで。
JaCoCoはEMMAの後継となるコードカバレッジツールです。なんやかんやで良い感じらしいです。
Java Agentによってコードカバレッジの測定が行われますので、JVMオプションの設定が必要になります。ここポイント。試験に出ます。
test-compileフェーズでjacoco:prepare-agentを実行すると、jacocoArgsにJVM用のオプションが設定されます。 これをmaven-surefire-pluginのargLineに渡せばOKです。デフォルトでJUnitのJVMがフォークされるので、テスト終了と同時に、target/jacoco.execへ計測結果が出力されます。
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.5.201403032054</version>
<executions>
<execution>
<id>prepare-agent</id>
<phase>test-compile</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>net/afnf/blog/**</include>
</includes>
<excludes>
<exclude>net/afnf/blog/domain/**</exclude>
<exclude>net/afnf/blog/mapper/**</exclude>
</excludes>
<propertyName>jacocoArgs</propertyName>
<append>true</append>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.16</version>
<configuration>
<argLine>${jacocoArgs}</argLine>
</configuration>
</plugin>
propertyNameやargLineはデフォルト設定でOKなので、実際には未設定でもかまいません。
前回は、jetty:startを使って統合テストのJettyを起動する方法を紹介しましたが、この場合、MavenのJVMから直接起動されてしまいます。このため、以下のようにMAVEN_OPTS環境変数でJava Agentの設定を行う必要があります。
export MAVEN_OPTS=-javaagent:/home/xxxxxx/.m2/repository/org/jacoco/org.jacoco.agent/0.6.5-SNAPSHOT/org.jacoco.agent-0.6.5-SNAPSHOT-runtime.jar=destfile=/home/xxxxxx/blog-java1/target/jacoco.exec,includes=net/afnf/blog/**,excludes=net/afnf/blog/domain/**:net/afnf/blog/mapper/**,append=true
前述のjacocoArgsは使えません。メンテナンス性が最悪。
さらに、MavenのJVMが終了してようやくtarget/jacoco.execが書き出されるため、テストとレポート生成のMaven実行を分けなければなりません。面倒です。
mvn -Pstaging-test clean verify
mvn jacoco:report
じゃあどうするか。
統合テスト用のJettyを、別のJVMで起動させればよいのです。ということで、jetty:startではなく、jetty:run-forkedを使います。
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.1.0.v20131115</version>
<executions>
<execution>
<id>run-forked-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>stop</goal>
<goal>run-forked</goal>
</goals>
<configuration>
<contextPath>/${pom.contextPath}</contextPath>
<jvmArgs>-Djetty.port=${selenium.jettyport} ${jacocoArgs}</jvmArgs>
<waitForChild>false</waitForChild>
<reload>manual</reload>
<scanIntervalSeconds>0</scanIntervalSeconds>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
<configuration>
<systemPropertiesFile>src/filters/${pom.confdir}/config.properties</systemPropertiesFile>
<reload>automatic</reload>
<scanIntervalSeconds>1</scanIntervalSeconds>
<webApp>
<contextPath>/${pom.contextPath}</contextPath>
</webApp>
<stopKey>key1</stopKey>
<stopPort>9999</stopPort>
<stopWait>10</stopWait>
</configuration>
</plugin>
デフォルトだと、Jettyが終了するまで制御が返りません。waitForChild=falseとすることでJetty起動後に制御が戻り、integration-testフェーズが実行されます。
jvmArgsがキモです。jacocoArgsを設定することで、カバレッジの計測が可能になります。
統合テスト終了後、post-integration-testのjetty:stopによりフォークしたJVMが終了し、jacoco.execが書き出されます。append=trueとしたので上書きにならず、JUnitの計測結果に追記されます。
reload、scanIntervalSeconds、daemonは無くてもOKです。なんとなく設定しました。
ちなみにwaitForChildですが、古いドキュメントには記載があるのですが、新しいドキュメントにはありません。実は非推奨だったりするのでしょうか。
2014/11/23追記:waitForChildの説明が追加されていました。
http://www.eclipse.org/jetty/documentation/current/jetty-maven-plugin.html
これは簡単で、jacoco:reportを実行するだけです。target/jacoco.execからHTML形式のレポートが生成されます。indexはtarget/site/jacoco/index.htmlです。
生成結果はこんな感じです。参考までにzip置いときます。
commonパッケージのカバレッジが低いのは、SMTP関連のテストをサボっているからです。
そんなこんなで、一発で単体テスト+統合テスト+レポート生成まで行けるようになりました。
mvn -Pstaging-test clean verify jacoco:report
いい感じ。