JaCoCoカバレッジレポートをPRにコメントしてくれる機能が欲しい！（Codecov使えない人向け）

# はじめに
皆さんはテストカバレッジとってますか？Codecovはとても便利でしたよね！
ですが今はセキュリティ的に使えないところも多いのではないでしょうか？自分が探した限りでは代替になりえそうなものがなかなか無く[^1]、テストカバレッジを意識したレビューがし辛い状況が続いていました。
そんな状況を打開すべく、今回は外部サービスに頼らずにカバレッジ結果をPRにコメントしてくれる設定を試してみたいと思います。
[^1]: GitLabのテストカバレッジ機能は便利そうでしたが今回はGitHubで使えるものを探しました。

完成イメージは↓こんな感じ

<img width=500px src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106116/1a0c9357-b5ea-dcf8-da44-bd206fcc92a7.png" />


# 1. JaCoCoの設定
※ JaCoCo設定済みの方はここは飛ばして<a href="#2-github-actionsの設定">2. GitHub Actionsの設定</a>を御覧ください。


今回は[jacoco-android-gradle-plugin](https://github.com/arturdm/jacoco-android-gradle-plugin)というGradleプラグインを利用します。簡単に設定できるのでおすすめです。
```kotlin:build.gradle
buildscript {
    repositories {
        maven { url = "https://plugins.gradle.org/m2/" }
    }
    dependencies {
        classpath("com.dicedmelon.gradle:jacoco-android:0.1.5")
    }
```

テストカバレッジから除外したいmoduleがあったので対象を選択出来るようにgradleファイルをjacoco用に分けます。
こうすることで任意のmoduleにapplyするだけでカバレッジを取得できるようになります。

```gradle:jacoco.gradle
apply plugin: 'com.dicedmelon.gradle.jacoco-android'

tasks.withType(Test) {
    // Robolectricを使っている場合は設定必須
    // https://github.com/robolectric/robolectric/issues/2230
    jacoco.includeNoLocationClasses true

    // JDK 11を使っている場合は設定必須
    // https://github.com/gradle/gradle/issues/5184#issuecomment-391982009
    jacoco.excludes = ["jdk.internal.*"]
}

jacoco {
    toolVersion = "0.8.8"
}

jacocoAndroidUnitTestReport {
    csv.enabled false
    html.enabled false
    // 後述のGitHub Actionsではxmlを利用するのでxmlのみtrueに。
    xml.enabled true

    // 自動生成されるDaggerやBindingクラスなどはカバレッジから除外する
    excludes += [
            '**/R.class',
            '**/R$*.class',
            '**/BuildConfig.*',
            '**/Manifest*.*',
            '**/*Test*.*',
            'androidx/**/*.*',
            '**/*Hilt*.*',
            '**/*Dagger*.*',
            '**/*$ViewInjector*.*',
            '**/*MembersInjector*.*',
            '**/*GeneratedInjector*.*',
            '**/*_Factory.*',
            '**/*_Provide*Factory*.*',
            '**/*_ViewBinding*.*',
            '**/AutoValue_*.*',
            "**/*Binding*.*",
            '**/*Module*.*',
    ]
}
```

最後に適用したいモジュールでapplyします。

```gradle:app/build.gradle
apply from: "$rootDir/jacoco.gradle"
```
or 
```kotlin:app/build.gradle.kts
apply(from = "$rootDir/jacoco.gradle")
```

## 動作確認
 JaCoCoの設定が出来ているかコマンド叩いて確認してみましょう。`BUILD SUCCESSFUL`が出力されれば成功です。
また、ファイルは `プロジェクトルート/module名/build/jacoco` に出力されているはずです。
```sh
# 自身のプロジェクトでbuildTypesやproductFlavorsを変えている場合はそれに合わせて`Debug`の箇所を書き換えてください
cd ~/プロジェクトルート
./gradlew jacocoTestDebugUnitTestReport
```

# 2. GitHub Actionsの設定

JaCoCoのレポート出力には[madrapps/jacoco-report](https://github.com/marketplace/actions/jacoco-report)を使います。

|項目 |説明  |
|---|---|
|paths  |カンマ区切りでxmlファイルを渡す  |
|token  |secrets.GITHUB_TOKENを設定すればOK  |
|min-coverage-overall  | 全体のカバレッジの合格ライン |
|min-coverage-changed-files  |変更したファイルのカバレッジの合格ライン |


```yml:.github/workflows/check_pr.yml
name: check pr
on:
  pull_request:
    branches:
      - 'main'
jobs:
  unit_test:
    runs-on: ubuntu-latest
    steps:
      - name: Check out
        uses: actions/checkout@v2
      - name: Set up JDK
        uses: actions/setup-java@v3
        with:
          distribution: 'zulu'
          java-version: 11
      - uses: gradle/gradle-build-action@v2
      - name: Run unit test and Measure coverage
        run: |
          ./gradlew --no-daemon jacocoTestDebugUnitTestReport
      - name: Publish Jacoco Report
        if: cancelled() != true
        uses: madrapps/jacoco-report@v1.3
        with:
          paths: |
            ${{ github.workspace }}/app/build/jacoco/jacoco.xml,
            ${{ github.workspace }}/repository/build/jacoco/jacoco.xml
          token: ${{ secrets.GITHUB_TOKEN }}
          min-coverage-overall: 40
          min-coverage-changed-files: 60
```

以上で設定完了です。

それでは試しに、既にunit test作成済みのExampleARepositoryというクラスにget2関数を追加する[プルリク](https://github.com/tarumzu/jacoco-sample/pull/3)を作ってみます。

```kotlin:repository/src/main/java/com/example/jacocosample/repository/ExampleARepository.kt
class ExampleARepository {
    fun get() = "test"

    fun get2() = "test"
}
```

無事botが結果をコメントしてくれました！
先述のmin-coverageで設定したしきい値を元に合格は:green_apple:、不合格は:x:で表示されます。
<img width=500px src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/106116/1a0c9357-b5ea-dcf8-da44-bd206fcc92a7.png" />

今回利用したサンプルのコードみたい方は下記に置いておきますのでご自由にどうぞ。

https://github.com/tarumzu/jacoco-sample

# おわりに
正直なところ、Codecovと比べると前回からの増減がわからない、htmlレポートが見れないなど課題は多いです。（JaCoCoのhtmlレポートをCIのアーティファクトに保存するとかで改善はできそう）
まだまだ完璧とは言えないのでより良くなるように日々改善策を模索中です。もっとこうした方がいいよとか皆様のテストカバレッジ事情などあれば是非コメント下さい！色々語り合いましょう！
最後までお読みいただきありがとうございました。