コードカバレッジを見つつユニットテストを書く


対象読者

Kotlinで開発しているAndroidエンジニア

はじめに

みなさん、ユニットテストは書いてますか?
コードカバレッジはどうでしょうか?

コードカバレッジとは?

ソースコードのテストされた割合です。
測定手法がいくつかありますが、今回は2つだけご紹介します。

命令網羅(C0)

ソースコードの 各文 が実行されているかどうか。

fun hoge(x: Int) {
    println("hoge")
    if (x > 0) {
        println("fuga")
    }
}

hoge(x = 1) だけで C0:100%

分岐網羅(C1)

ソースコードの 各条件 が実行されているかどうか。

fun hoge(x: Int) {
    println("hoge")
    if (x > 0) {
        println("fuga")
    }
}

hoge(x = 1)hoge(x = 0)C1:100%

コードカバレッジ、何か嬉しいことがあるの?

ユニットテストが充分か?の判断基準の一つとして使えます。
例として、既存コードのリファクタリングを考えてみます。

既存コード

fun hoge(x: Int): String {
    if (x >= 3) return "many"
    if (x == 2) return "two"
    if (x == 1) return "one"
    if (x == 0) return "zero"
    return "other"
}

ユニットテストを書く

@Test
fun hogeTest() {
    assert(hoge(3) == "many")
    assert(hoge(2) == "two")
    assert(hoge(1) == "one")
    assert(hoge(0) == "zero")
}

でも、このユニットテストで充分なのだろうか・・・?

そこでコードカバレッジ!

コードカバレッジを計測する方法

  • Android Studio
  • JaCoCo 今回はこちらをご紹介
  • Other...?

JaCoCoの準備

デフォルト設定だと、
Kotlinが計測対象になりません

arturdm/jacoco-android-gradle-plugin Issue 37JaCoCoの設定 を参考にすればOK

※上記の設定は build variants も考慮されていてステキ

カバレッジ結果をみてみる

$ gradlew jacocoDebugReport 実行後に、

app/build/reports/jacoco/jacocoDebugReport/html/index.html を開きましょう。

アプリ全体のレポート

クラスごとのレポート

クラス内の各関数ごとのレポート

ソースコードレベルのレポート

緑:分岐網羅 OK
黄:分岐網羅 NG(片方の分岐しか実行されてない、など)
赤:一度も実行されていない

テストコードを足す

カバレッジレポートを見たところ、ユニットテストに不足があることがわかりました。
テストコードを追加しましょう。

@Test
fun hogeTest() {
    assert(hoge(3) == "many")
    assert(hoge(2) == "two")
    assert(hoge(1) == "one")
    assert(hoge(0) == "zero")
    assert(hoge(-1) == "other") // ★追加テストコード
}

無事、カバレッジ100%

これで、ある程度信頼できるユニットテストができました。
なので、リファクタリングも怖くありません。

Kotlinっぽくしてみる

fun hoge(x: Int): String =
    when {
        x >= 3 -> "many"
        x == 2 -> "two"
        x == 1 -> "one"
        x == 0 -> "zero"
        else -> "other"
    }

分岐網羅100%&ユニットテストも通っているので、大丈夫そうです。

補足

  • カバレッジ100%だからユニットテスト完璧、ではない
    • でも、判断基準の一つとして使えます
  • カバレッジ100%必達では無い
    • 例えばユニットテスト書きづらいところは、手動で確認しても良いと思います