15
11

More than 3 years have passed since last update.

Gradle6系 + Jacoco + マルチモジュール + フルKotlin + Android + Robolectric環境でユニットテストのカバレッジを出す

Posted at

何番煎じなのか分かりませんが、Gradleが6系になりまた記述方法が変わったりしたので気にせずに記事にします。

  • Gradle: 6.0.1
  • Android Gradle Plugin: 3.5.3

の環境で検証しています。
また、カバレッジの算出に不要な記述は省いています。

実際のプロジェクトでどのように書くか気になる場合は以下を参照
https://github.com/ohmae/touch-icon-extractor

シングルモジュール

まずはマルチモジュールの前に各モジュールの中でのカバレッジ算出です。

apply plugin: "jacoco"

android {
    testOptions {
        unitTests.includeAndroidResources = true
        unitTests.all {
            jacoco {
                includeNoLocationClasses = true
            }
        }
    }
}

jacoco {
    toolVersion = "0.8.5"
}

task jacocoTestReport(
    type: JacocoReport,
    dependsOn: "testDebugUnitTest",
    group: "verification"
) {
    reports {
        xml.enabled = true
        html.enabled = true
    }
    getSourceDirectories().from = "${projectDir}/src/main/java"
    getClassDirectories().from = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug")
    getExecutionData().from = "${buildDir}/jacoco/testDebugUnitTest.exec"
}

これだけです。ビルドバリアントに依存する部分がありますので、その部分は適宜書き換えてください。

android {
    testOptions {
        unitTests.all {
            jacoco {
                includeNoLocationClasses = true
            }
        }
    }
}

上記の記述がないと、Robolectricを使ったテストのカバレッジが算出できません。

getClassDirectories().from = fileTree(dir: "${buildDir}/tmp/kotlin-classes/debug")

上記の部分はコンパイルされたクラスファイルの指定です、Androidでは自動的に生成されるクラスを除外する記述を行いますが、(現時点では)javaとkotlinでクラスファイルの場所が違っており、フルKotlinのプロジェクトならKotlinのクラスファイルを指定するだけで除外する必要はありません。

マルチモジュール

マルチモジュールでプロジェクト全体のカバレッジを出すには、各プロジェクトごとのカバレッジ情報を集める必要があります。
これはルートプロジェクトのGradleファイル上でタスクを定義します。

apply plugin: "jacoco"

jacoco {
    toolVersion = "0.8.5"
}

task jacocoMerge(
    type: JacocoMerge,
    group: "verification"
) {
    gradle.afterProject { project, _ ->
        if (project.rootProject != project && project.plugins.hasPlugin('jacoco')) {
            executionData "${project.buildDir}/jacoco/testDebugUnitTest.exec"
        }
    }
}

task jacocoMergedReport(
    type: JacocoReport,
    dependsOn: [tasks.jacocoMerge],
    group: "verification"
) {
    getExecutionData().from = jacocoMerge.destinationFile

    gradle.afterProject { project, _ ->
        if (project.rootProject != project && project.plugins.hasPlugin('jacoco')) {
            getSourceDirectories().from += "${project.projectDir}/src/main/java"
            getClassDirectories().from += project.fileTree(dir: "${project.buildDir}/tmp/kotlin-classes/debug")
        }
    }
    reports {
        xml.enabled = true
        html.enabled = true
    }
}

ルートプロジェクトはサブプロジェクトよりも先に評価されるため。そのままではサブプロジェクトの情報を集められない。
gradle.afterProject を使って、各プロジェクトが評価された後にクロージャを経由して情報を収集する。
クロージャではルートプロジェクト自身と、Jacocoを使っていない、カバレッジ算出対象外のプロジェクトを除外しています。
モジュールごとの算出と同じものを集めているだけといった形です。

jacocoMergeの依存関係で各モジュールのテスト実行をさせたかったのですがうまくいかず、補足いただけると幸いです。

以上です。

15
11
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
15
11