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

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` として、下記のスクリプトを置いておきます。

```groovy: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`に下記の記述を追加します。

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

## タスクの実行

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

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

![image](https://qiita-image-store.s3.amazonaws.com/0/8708/49f496e3-95c5-56f9-6f47-5fd217302a8c.png)

## その他メモ

### excludesの設定

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