LoginSignup
11
8

More than 5 years have passed since last update.

AndroidのLocal Unit Testsのカバレッジをjacocoで取得する

Last updated at Posted at 2016-05-17

https://developer.android.com/training/testing/start/index.html
src/test/java 以下に書いていくテストは、"Local Unit Test"というそうです。
一方、src/androidTest/java 以下に書くテストは、"Instrumented Test"というそうです。

今のプロジェクトでは、テストの実行速度を優先して"Local Unit Test"を書いており、またそのカバレッジを取得しようとしています。
なので、その設定をまとめました。

実際には、
https://blog.gouline.net/code-coverage-on-android-with-jacoco-92ec90c9355e#.elikwgbjp
に書いてあることがほとんどです。

最終的に設定したものが、 https://github.com/noboru-i/kyouen-android/pull/26 のPRにまとまってます。(daggerも同時に入れてしまっていますが)

gradleスクリプトを記述

tasks/jacoco.gradle として、下記のスクリプトを置いておきます。

tasks/jacoco.gradle
apply plugin: 'jacoco'

jacoco {
    toolVersion = "0.7.6.201602180812"
}

project.afterEvaluate {
    // Grab all build types and product flavors
    def buildTypes = android.buildTypes.collect { type ->
        type.name
    }
    def productFlavors = android.productFlavors.collect { flavor ->
        flavor.name
    }
    // When no product flavors defined, use empty
    if (!productFlavors) productFlavors.add('')
    productFlavors.each { productFlavorName ->
        buildTypes.each { buildTypeName ->
            def sourceName, sourcePath
            if (!productFlavorName) {
                sourceName = sourcePath = "${buildTypeName}"
            } else {
                sourceName = "${productFlavorName}${buildTypeName.capitalize()}"
                sourcePath = "${productFlavorName}/${buildTypeName}"
            }
            def testTaskName = "test${sourceName.capitalize()}UnitTest"
            // Create coverage task of form 'testFlavorTypeCoverage' depending on 'testFlavorTypeUnitTest'
            task "${testTaskName}Coverage"(type: JacocoReport, dependsOn: "$testTaskName") {
                group = "Reporting"
                description = "Generate Jacoco coverage reports on the ${sourceName.capitalize()} build."
                classDirectories = fileTree(
                        dir: "${project.buildDir}/intermediates/classes/${sourcePath}",
                        excludes: [
                                '**/R.class',
                                '**/R$*.class',
                                '**/*$ViewInjector*.*',
                                '**/*$ViewBinder*.*',
                                '**/BuildConfig.*',
                                '**/Manifest*.*',
                                '**/*$Lambda$*.class'
                        ]
                )
                def coverageSourceDirs = [
                        "src/main/java",
                        "src/$productFlavorName/java",
                        "src/$buildTypeName/java"
                ]
                additionalSourceDirs = files(coverageSourceDirs)
                sourceDirectories = files(coverageSourceDirs)
                executionData = files("${project.buildDir}/jacoco/${testTaskName}.exec")
                reports {
                    xml.enabled = true
                    html.enabled = true
                }
            }
        }
    }
}

gradleスクリプトを適用する

app/build.gradleに下記の記述を追加します。

apply from: '../tasks/jacoco.gradle'

タスクの実行

./gradlew :app:testDebugUnitTestCoverage
を実行します。

app/build/reports/jacoco/testDebugUnitTestCoverage/html/index.html
にhtml形式で結果が出力されています。

image

その他メモ

excludesの設定

リンク元では '**/*$Lambda$*.class' は無かったですが、retrolambdaで生成したクラス部分でエラーになったので、 追加しました。
どこかのページを参考にした気がするのですが、忘れてしまいました。
https://github.com/evant/gradle-retrolambda/issues/145 を見ると、いくつかのバージョンでは動作するようです。
ほかにもこういった変換を行っているライブラリを使う際には、追加が必要なのかもしれないです。

11
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
8