play java 2.2系アプリをCircleCIを使って、CI環境を構築した際のメモ。
下記を満たすように構築。
- ユニットテスト用のDBを自前で作成
- テスト用のapplication.confを指定
- カバレッジ測定
- コードの静的解析
- CircleCI上で見たいのでテスト結果などはなるべくhtmlで保存
手順はcircle.ymlに記述していく。
自前のDB、ユーザの構築
databaseの項目に、スキーマとユーザ作成を記述。
database:
override:
- mysql -uroot -e 'CREATE DATABASE db_unittest;'
- mysql -uroot -e 'CREATE USER app_user@localhost IDENTIFIED BY "app";'
flywayでmigration
DDLとコード値のマスタテーブルの初期データ投入までをflywayにまかせる。
resolvers += "Flyway" at "http://flywaydb.org/repo"
addSbtPlugin("org.flywaydb" % "flyway-sbt" % "3.2.1")
DBへの接続情報がちらばってしまうのが微妙ですが、固定のままでいくので割り切ってbuild.sbtに記述。sqlの置き場所をファイルシステムに変更。
seq(flywaySettings: _*)
flywayUrl := "jdbc:mysql://localhost/db"
flywayUser := "app_user"
flywayPassword := "app"
flywayLocations := Seq("filesystem:db/migration")
ユニットテスト用のurlはコマンドの引数で渡すかたちをとる。
play -Dflyway.url=jdbc:mysql://localhost/db_unittest flywayMigrate
jacoco4sbtでテストとカバレッジ
テストとカバレッジの測定をjacocoで行う
jacoco:cover
jacoco4sbtの設定
addSbtPlugin("de.johoop" % "jacoco4sbt" % "2.1.6")
- parallelExecutionをoffにしないとテスト結果のxmlがひとつにまとめられてしまう
- フレームがつくるクラスファイルを除外
- テスト用の設定ファイルをSystem Propertyに設定することで指定
jacoco.settings
parallelExecution in jacoco.Config := false
jacoco.excludes in jacoco.Config := Seq(
"controllers*",
"*Routes*",
"controllers*routes*",
"views*html*",
"controllers*javascript*",
"controllers*ref*",
)
testOptions in Test += Tests.Argument("-verbosity", "1")
testOptions in jacoco.Config += Tests.Setup( () => System.setProperty("config.file", "conf/application_test.conf") )
カバレッジの閾値を設定したい場合は、以下を追加
how-to-fail-build-on-low-test-coverage-with-activator-sbt
jacoco.thresholds in jacoco.Config := Thresholds(
instruction = 50,
method = 50,
branch = 50,
complexity = 50,
line = 50,
clazz = 50)
findbugs4sbtでコード解析
バグの要因になりやすい箇所を指摘してくれる。標準はxmlのレポートが生成される。
addSbtPlugin("de.johoop" % "findbugs4sbt" % "1.3.0")
- 不要クラスを除外
- レポートのファイル名を変更
- レポートタイプをhtmlに変更
findbugsSettings
findbugsExcludeFilters := Some(<FindBugsFilter>
<Match>
<Or>
<Package name="controllers" />
<Package name="views.html" />
<Class name="routes" />
<Class name="routes$javascript" />
<Class name="routes$ref" />
</Or>
</Match>
</FindBugsFilter>)
findbugsReportPath := Some(crossTarget.value / "findbugs" / "report.html")
findbugsReportType := Some(ReportType.Html)
下記コマンドで、target/scala-2.10/findbugsにレポートが出力される。
play findbugs
テストの成果物を保存
テスト後の後処理で、成果物の保存・加工を行う。
$CIRCLE_TEST_REPORTS/に、テスト結果のxmlをおくと、Test Results
で成功、失敗の件数が表示される。
test:
post:
- play findbugs
- mkdir -p $CIRCLE_TEST_REPORTS/junit/
- mkdir -p $CIRCLE_TEST_REPORTS/findbugs/
- mkdir -p $CIRCLE_TEST_REPORTS/jacoco/
- cp target/test-reports/* $CIRCLE_TEST_REPORTS/junit/
- cp -r target/scala-2.10/jacoco/html/ $CIRCLE_TEST_REPORTS/jacoco/
- cp target/scala-2.10/findbugs/* $CIRCLE_TEST_REPORTS/findbugs/
junitの結果をmaven-surefire-report pluginでhtmlに変換
テスト項目と結果を見るのにxmlではつらいので、苦肉の策でmvnコマンドを使う。
(いけてないのでなんとかしたい)
mvnを動かすためだけのpom.xml
play makePom
で、もとになるpom.xmlファイルを作成。
securesocialが依存関係が解決できないので、その部分はコメントアウト。
<!--
<dependency>
<groupId>securesocial</groupId>
<artifactId>securesocial_2.10</artifactId>
<version>2.1.2</version>
</dependency>
-->
レポートプラグインの追加
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>2.3</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<plugin>
<artifactId>maven-project-info-reports-plugin</artifactId>
<configuration>
<dependencyLocationsEnabled>false</dependencyLocationsEnabled>
</configuration>
</plugin>
</plugins>
</reporting>
レポートのxmlファイルを移動
sure-fire-pluginで対象のxmlがあるディレクトリをうまく指定できなかったので、デフォルト設定のディレクトリに移す作戦をとる。(残念すぎる・・・)
- mkdir -p target/surefire-reports
- cp target/test-reports/* target/surefire-reports
あとは、mvn site
を実行。site以下のsurefire-report.htmlから、テスト結果を見られる。
Artifacts
から、保存したものをたどっていけます。
まとめ
ようやく、テストとコード解析を伴ったCIでの開発環境が整った!
Redmineのチケットごとにブランチを切っているので、featureブランチにpushする度にテストとコード解析が走るので、安心してリファクタリングができる。カバレッジが高ければ、それだけ、デグレしにくいという目安にもなる。
課題は、findbugsやカバレッジの数値の推移がこれではわからないということ。CircleCI自体は、毎回使い切りの思想なので、別のサービスにデータを送るしかなさそう。