【Android】jacocoでコードカバレッジを取る
追記
Kotlin対応
最近UTを書くようになってきたのでカバレッジを取ってみました。Gradleにjacocoのプラグインがあるのでそれを使います。
build.gradleはDroidkaigi2017のbuild.gradleを参考にしました。
apply 'jacoco' apply plugin: 'com.android.application' android { // Settings for Android... } jacoco { toolVersion = "0.7.7.201606060606" } // A list of directories which should be included in coverage report def coverageSourceDirs = ['src/main/java'] // A list of files which should be excluded from coverage report since they are generated and/or framework code def coverageExcludeFiles = ['**/R.class', '**/R$*.class', '**/com/android/**/*.*', '**/BuildConfig.class', '**/*Activity*.class', '**/*Fragment*.class', '**/*Receiver.class', '**/*Manifest*.class', '**/*Application*.class'] task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." reports { xml.enabled true html.enabled true csv.enabled false xml.destination "${buildDir}/reports/jacoco/jacocoTestReport.xml" html.destination "${buildDir}/reports/jacoco/html" classDirectories = files( fileTree( dir: "${buildDir}/intermediates/classes/uiTest/debug", exclude: coverageExcludeFiles)) } sourceDirectories = files(coverageSourceDirs) executionData = files "${buildDir}/jacoco/testUiTestDebugUnitTest.exec" doLast { println "jacoco xml report has been generated to file://${buildDir}/reports/jacoco/jacocoTestReport.xml" println "jacoco html report has been generated to file://${reports.html.destination}/index.html" } } dependencies { // For dependencies... }
まずapply 'jacoco'でプラグインを適用します。そしてjacocoプラグインのバージョンを指定します。
jacoco {
toolVersion = "0.7.7.201606060606"
}
バージョンの一覧はここにあります。
次にコードカバレッジのレポートを作るタスクを作ります。 jacocoプラグインにはJacocoReportというレポートを作成するタスクがあります。jacocoの解析対象はバイトコードのため、UTのタスク(test(ProductFlavor)DebugUnitTest)と同時に実行させる必要があるので依存させます。私の場合はuiTestというProductFlavorでUTを実行しているので依存させるタスク名はtestUiTestDebugUnitTestになります。タスク名がわからなかったら./gradlew tasksで調べます。
task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) {
}
あとはJacocoReportのページを参考に設定します。私の場合はActivityやFragment等のクラスはカバレッジに含めないようにしました。先ほど書いたようにjacocoの解析対象はバイトコードのため、reports.classDirectoriesにはビルド後のパスを設定します。executionDataのパスは"${buildDir}/jacoco/test(ProductFlavor)DebugUnitTest.exec"となるようです。
// A list of directories which should be included in coverage report def coverageSourceDirs = ['src/main/java'] // A list of files which should be excluded from coverage report since they are generated and/or framework code def coverageExcludeFiles = ['**/R.class', '**/R$*.class', '**/com/android/**/*.*', '**/BuildConfig.class', '**/*Activity*.class', '**/*Fragment*.class', '**/*Receiver.class', '**/*Manifest*.class', '**/*Application*.class'] task jacocoTestReport(type: JacocoReport, dependsOn: ['testUiTestDebugUnitTest']) { group = "Reporting" description = "Generate Jacoco coverage reports after running tests." reports { xml.enabled true html.enabled true csv.enabled false xml.destination "${buildDir}/reports/jacoco/jacocoTestReport.xml" html.destination "${buildDir}/reports/jacoco/html" classDirectories = files( fileTree( dir: "${buildDir}/intermediates/classes/uiTest/debug", exclude: coverageExcludeFiles)) } sourceDirectories = files(coverageSourceDirs) executionData = files "${buildDir}/jacoco/testUiTestDebugUnitTest.exec" }
結果は↓のような感じ
これでjacocoによるコードカバレッジが取れるようになりました。 次はCircleCIとCodecovを連携させてコードカバレッジをGitHubのREADMEに表示する方法について書きたいと思います。