はじめに
Android アプリ開発において、単体テストを作成することはデグレードを防ぐための最も基本的でかつ低コストな施策です。そこにカバレッジレポート出力があると、単体テストによってカバーされている行とされていない行を視覚的に把握することができ、単体テストの作成とコードレビューをより正確かつ効率的に行うことができます。
カバレッジレポートをチームで共有
この記事では、GitHub のプルリクにコメントとしてカバレッジレポートが投稿される設定を行うことで、それをチームで共有できるようにする設定を紹介します。
複数記事を予定しています
Android アプリ開発には様々な開発スタイルがあり、それらをすべて網羅してカバレッジレポートを解説すると長大な記事になるため、今回は基本的な内容に留めて、今後テーマを分けて複数記事の投稿を予定しています。
現在、以下の記事を公開しています。
記事の構成
今回はカバレッジレポートをチームで共有するための手順を以下の構成で解説しています。
- Gradle でカバレッジレポートを出力する
- Codecov と GitHub を連携する
- リポジトリに Codecov のための設定ファイルを置く
- CI で Codecov にカバレッジレポートをアップロードする
Codecov を使わずに HTML 形式のカバレッジレポートを出力して運用するケースは、こちらの記事で解説しています。
設定が簡単になった
Gradle でカバレッジレポートを出力する設定方法は、Codecov 公式で JaCoCo Plugin を使う方法が紹介されています。しかし Android のローカル単体テストを対象とする場合の設定が難解です。 近年、Kotlin 公式のプラグインである Kover がリリースされ、それを使用することで、 最短2行のシンプルな記述でカバレッジレポートの出力を設定できるようになりました。
また、以前からある Jacoco の設定方法はこちらの記事で解説しています。
開発スタイルおよび環境
この記事では以下の開発スタイルおよび環境を想定しています。
- Android プロジェクト
- シングルモジュールだけでなくマルチモジュールにも対応しています。
- Kotlin Multiplatform Mobile プロジェクトでの設定方法は、最後に補足として紹介しています。
-
ローカル単体テスト
- Robolectric を使ったローカル単体テストにも対応しています。
- インストゥルメント化単体テストは Kover を使いませんが別の記事で解説する予定です。
- Gradle 8.1.1
- Android Gradle Plugin 8.0.2
- Kotlin 1.8.22
Gradle でカバレッジレポートを出力する
GitHub Actions 等の CI でカバレッジレポートを出力するために Gradle の設定を行います。
公式の設定例
設定方法は公式の GitHub リポジトリの kover-gradle-plugin/examples フォルダを参考にすれば良いです。
以下のような開発スタイルに対応した設定例が紹介されています。(一部抜粋)
フォルダ名 | モジュール | Gradle DSL の言語 |
---|---|---|
android/minimal_groovy/ | シングルモジュール | Groovy |
android/minimal_kts/ | シングルモジュール | Kotlin |
android/multiproject/ | マルチモジュール | Kotlin |
Kover のミニマムな設定方法
公式の設定例を参考にミニマムな設定をします。
まずプロジェクトの build.gradle に以下の設定を追加して、プロジェクト全体で Kover を使えるようにします。
plugins {
id 'org.jetbrains.kotlinx.kover' version '0.7.2' apply false
}
次にモジュールの build.gradle の plugins ブロックに以下の設定を追加します。
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
// 追加
id 'org.jetbrains.kotlinx.kover'
}
以前の書き方をお使いの場合は、こちらの設定を追加します。
apply plugin: "org.jetbrains.kotlinx.kover"
動作確認のために、以下の Gradle タスクを実行します。Debug
の部分はビルドタイプになります。
./gradlew koverHtmlReportDebug
ローカル単体テストが実行され、HTML 形式のカバレッジレポートの保存パスを標準出力されます。
Kover: HTML report for ':app' file:///Users/takada/work/android_app_template/app/build/reports/kover/htmlDebug/index.html
そのパスを Web ブラウザで開くと、このように表示されます。
パッケージ名やファイル名のリンクを辿ることで、個別 Kotlin ファイルのカバレッジを確認できます。
これだけの設定では、BuildConfig ファイルや Hilt によって自動生成されたクラスも表示されてしまいます。しかし Codecov で使う分には、いったん気にしなくて良いです。最終的には GitHub リポジトリで管理されているコードのみのカバレッジレポートになります。Codecov を使わずに HTML 形式のカバレッジレポートを運用する場合や ViewModel など特定種類のクラスに限定したカバレッジレポート出力を行う方法はこちらの記事で解説しています。
マルチモジュールの場合
マルチモジュールの場合はカバレッジレポートを出力したいすべてのモジュールで org.jetbrains.kotlinx.kover
プラグインを使えるようにします。
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
// 追加
id 'org.jetbrains.kotlinx.kover'
}
すでに Script Plugin 等で複数モジュールの設定を共通化している場合は、そこに org.jetbrains.kotlinx.kover
プラグインを使える設定を追加すれば良いです。
そしてアプリケーションモジュールの dependencies ブロックに、以下のようにカバレッジレポートを出力したいモジュール一覧を設定します。直接参照していないモジュールも設定可能です。
dependencies {
// 省略
// 追加
kover(project(':viewCommon'))
kover(project(':feature:home:presentation'))
kover(project(':feature:info:presentation'))
// こちらは直接参照していない2階層下のモジュール群
kover(project(':feature:info:usecase'))
kover(project(':feature:home:usecase'))
}
Codecov と GitHub を連携する
ここまでの手順で Gradle で Kover を設定したことで、カバレッジレポートを HTML ファイルとして出力できるようになりました。次は Codecov と GitHub を連携することで、プルリクのコメントにカバレッジレポートを投稿する設定を行います。
まず Codecov に GitHub アカウントでログインします。
カバレッジレポートを出力したいリポジトリの setup repo
をクリックします。
CODECOV_TOKEN が取得できます。流出しないように注意してください。
次に CI の設定を行いますが、 GitHub Actions をお使いの場合は Actions Secrets に CODECOV_TOKEN を設定します。( リポジトリ → Settings → Secrets and variables → Actions)
Codecov アプリケーションを GitHub に追加する
Codecov のユーザアイコンから Install codecov app を選択して、Codecov アプリケーションを GitHub にインストールします。
リポジトリに Codecov のための設定ファイルを置く
Android プロジェクトのリポジトリ直下に以下の内容で codecov.yml
ファイルを設置します。
coverage:
status:
project: off
patch: off
このファイルでカバー率が何パーセント以上下がったらCIを失敗にする設定が出来ますが、今回はカバレッジレポートの表示のみを行いたいので無効化します。
CI で Codecov にカバレッジレポートをアップロードする
GitHub Actions をお使いの場合
GitHub Actions をお使いの場合は、PUSH ごとに行われるワークフローに以下の2ステップを追加すれば良いです。
name: check
on:
push:
branches:
- main
pull_request:
types:
- opened
- synchronize
- reopened
jobs:
check:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-java@v3
with:
distribution: 'adopt'
java-version: '17'
- uses: gradle/gradle-build-action@v2
# 追加
# 単体テストの実行 + XML 形式のカバレッジレポート出力
- run: ./gradlew koverXmlReportDebug
# Codecov にカバレッジレポートをアップロード
- uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
# アプリケーションモジュールの XML 形式のカバレッジレポートのパスを指定
files: ./app/build/reports/kover/reportDebug.xml
fail_ci_if_error: true
手元の実行では koverHtmlReportDebug
タスクを実行していましたが、CI では koverXmlReportDebug
を実行します。Codecov でサポートされているカバレッジレポートファイルの形式が HTML でなく XML だからです。
GitHub Actions 以外をお使いの場合
GitHub Actions 以外の CI をお使いの場合は Codecov Uploader を使用します。
CI のステップに以下のシェルスクリプトを追加します。
CODECOV_TOKEN が環境変数に設定されていることが前提です。
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
./codecov -t ${CODECOV_TOKEN} -f ./app/build/reports/kover/reportDebug.xml
まとめ
この記事では Android プロジェクトで Kover を用いてカバレッジレポートを出力する Gradle タスクの設定方法と Codecov を使ってプルリクでカバレッジレポートをチームで共有する設定を紹介しました。
今回は基本的な内容のみを説明しましたが、今後、Android アプリの様々な開発スタイルに対応した応用的な内容を説明する予定です。
補足
kotlin Multiplatform Mobile プロジェクトの場合
kotlin Multiplatform Mobile プロジェクトの場合でも設定方法は同じです。注意するべき点としては、JVM で動作する単体テストのみカバレッジレポートが出力されるという点です。Android / iOS のエミュレータ/シミュレーター/実機で動作する単体テストには対応していません。
また、Kotlin Multiplatform モジュールで JVM 向けのビルドを追加し、JVM だけで動作する単体テストでカバレッジを担保している場合は、Kover のタスク名に Android のビルドタイプは付けないです。
kotlin {
// 略
android {
compilations.all {
kotlinOptions {
jvmTarget = "17"
}
}
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "shared"
}
}
// JVM 向けビルドを追加
jvm()
// 略
}
# こちらのコマンドでカバレッジレポートが出力される
./gradlew koverHtmlReport
./gradlew koverXmlReport
JVM だけで動作する単体テスト書く例としては Mockk を使う代わりに iOS での単体テスト実行を諦めたケースが該当します。