12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android + Kotlin + PITでテストコードをテストする

Last updated at Posted at 2018-10-11

はじめに

PITを使用してKotlinなAndroidプロジェクトでMutation Testingを導入するまでのメモです。

Mutation Testing

テストコードが正しいかを計測するために、Mutant Testingという手法があります。
Mutant Testingではプロダクトコードを機械的に変更し、変更されたコードに対してテストを実行します。そしてテストが失敗するかを確認することで、プロダクトコードの振る舞いの変更をテストコードが検知できるかをチェックする手法です。

ミューテーション解析 - Wikipedia

PIT

今回はMutation TestingツールとしてPITを紹介します。PITはJavaとその他JVM言語用のMutation Testingツールです。検索するときはpitestで検索すると良いです。
PITの素晴らしい点は、3rdパーティー製Android用Gradle Pluginが公開されており、導入が容易なところです。

その他Java向けMutataion Testingツールとの比較は下記にまとまっていました。PITのドキュメントです。
こちらのページでは、どのようなツールがあるかとそれぞれどのような設計で実装されているかが記載されています。
Java Mutation Testing Systems

Android + PIT

AndroidプロジェクトでPITを実行できるようにするために、Android版gradle-pitest-pluginを使用します。
GitHub - koral--/gradle-pitest-plugin: Gradle plugin for PIT Mutation Testing in Android projects

Pluginの追加

build.gradle
buildscript {
    ..
    dependencies {
        ..
        classpath 'pl.droidsonroids.gradle:gradle-pitest-plugin:0.1.7'
    }
}
app/build.gradle
apply plugin: 'pl.droidsonroids.pitest'

もともとgradle-pitest-pluginがあり、Android版gradle-pitest-pluginではそのpluginをAndroidで使えるように修正したものです。オプションについては元のplguinのページを参照します。
Gradle plugin for PIT Mutation Testing | gradle-pitest-plugin

実行をするのに最低限必要な設定は下記でした。

app/build.gradle
pitest {
    targetClasses = ['my.package'] //テストしたいpackage
}

実行

下記コードに対してPITを実行します。

fun plusNumberChecker(number: Int): String {
    if (number < 0) {
        return "NG"
    }
    return "OK"
}
@Test
fun plusNumberChecker_NG() {
    assertThat(plusNumberChecker(-1), equalTo("NG"))
}

@Test
fun plusNumberChecker_OK() {
    assertThat(plusNumberChecker(0), equalTo("OK"))
}

pitestタスクを実行します。

./gradlew pitest //すべてのVariantに対して実行
or
./gradlew pitest[Variant]

デフォルトの設定ですと、app/build/reports/pitest/variant/日時にHtmlレポートが出力されます。

下記が実際に出力されたレポートです。

スクリーンショット 2018-10-12 2.27.59.png スクリーンショット 2018-10-12 2.18.02.png

Mutationsにコードをどのように変更したかが記載されています。
PITではコードをどのように変更するかの定義をmutatorと呼んでいます。mutatorの一覧と詳細がMutation operatorsのページにまとまっているので、レポートと照らし合わせながら確認します。
Mutation operators

今回は以下のmutatorによってコードが変更されました。

  • changed conditional boundary: <<=に変更
  • negated conditional boundary: <>=に変更
  • mutated return of Object value: 戻り値をnullに変更 × 2

また、4回の変更すべてでテストが失敗したので(KILLED)、Mutation Coverageは100%(4/4)です。

試しに、テストコードを変更してplusNumberChecker_OKのassertionを削除します。必ずパスするテストコードになりました。

@Test
fun plusNumberChecker_NG() {
    assertThat(plusNumberChecker(-1), equalTo("NG"))
}

@Test
fun plusNumberChecker_OK() {
    plusNumberChecker(0)
}

上記テストコードでPITを実行した結果のレポートです。

スクリーンショット 2018-10-12 2.26.50.png スクリーンショット 2018-10-12 2.27.01.png

最初のレポートと比較すると、結果が以下のように変わっています。

  • changed conditional boundaryをした(<<=に変更した)コードのテストがパス(SURVIVED)
  • mutated return of Object valueをした(戻り値をnullに変更した)コードのうち1つのテストがパス
  • 4回の変更のうちテストが失敗したのは2件なので、Mutation Coverageは50%

Mutation Testingではこのように、プロダクトコードの変更を検知できないテストコードを見つけだすことができます。

Kotlinでの制約

さきほどのMutation Testingでは戻り値をnullに変更するmutatorが使われました。
ただ、plusNumberCheckerメソッドの戻り値はNon-Nullです。これでは振る舞いだけでなくIFまで変わってしまいます。

PITでは、Kotlinにおいてノイズになってしまうmutatorへの対応を下記issueで議論しています。
improve kotlin support · Issue #260 · hcoles/pitest · GitHub

こちらのissueによると、1.3.0でNonNullのアノテーションを考慮する新しいmutatorが複数実装されました。
それらのmutatorはデフォルトでは有効になっておらず、NEW_DEFAULTSというmutator setに含まれているようなので、使用するmutator setを変更します。

app/build.gradle
pitest {
    ..
    mutators = ["NEW_DEFAULTS"]
}

この設定でPITを実行したレポートが以下です。

スクリーンショット 2018-10-12 2.55.38.png

Mutationsの項目の中で、mutated return of Object valuereplaced return value with ""に変わっています。名前からわかるとおり、戻り値を空文字にするmutatorに変更されました。

このように、PITではKotlinのサポートの開発も進めています。
pitest-kotlinというKotlinのpluginのプロジェクトもあるのですが、まだMaven Repositoryにあがっていないようでした。
GitHub - pitest/pitest-kotlin: Kotlin plugin for pitest

When the plugin is enabled pitest will avoid creating junk mutations in code that uses

・ de structuring code
・ null casts
・ safe casts
・ elvis operator

READMEには上記の記述もあり、今後のアップデートが気になるところです。

おわりに

KotlinなAndroidプロジェクトでPITを導入する手順を紹介しました。Gradle Pluginが公開されているおかげで導入は容易です。
一方Kotlinコードのmutatorはこれから改善されていく状態ですので、引き続き情報のアップデートをしていく必要がありそうです。

12
6
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
12
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?