[Android]Androidでテストフィクスチャを使う

Android Gradle Plugin 7.1.0 からテストフィクスチャがサポートされたようなので試してみました。

https://developer.android.com/studio/preview/features#test-fixtures

テストフィクスチャはテストに必要な前提条件などを設定したりするためのものです。この機能を使うことによって、テストに必要なオブジェクトの定義やユーティリティメソッドなどを提供することができ、それらを Gradle の各モジュールのテストコードで参照することが可能になります。

今回試したプロジェクトは [こちら](https://github.com/watabee/TestFixturesSample) にアップしています。

# ライブラリモジュールでのテストフィクスチャの設定

Android ライブラリの Gradle モジュールでテストフィクスチャを提供する方法を見ていきます。ここではこのライブラリモジュールを仮に `data` モジュールとします。まずはこの `data` モジュールの `build.gradle` で以下のように設定します。

```groovy:data/build.gradle
android {
    ...
      
    testFixtures {
        enable true
    }
}
```

そして、このモジュール内で `src/testFixtures/java` ディレクトリを作成し、この中にテストフィクスチャとして提供したいオブジェクトなどを作成します。

注意点として、今のところテストフィクスチャで提供するオブジェクトなどは **Java ファイルで記述する必要**があるようです。
（https://issuetracker.google.com/issues/139438142 参照）

Kotlin はサポートされていないようなので注意してください。

```java:data/src/testFixtures/java/com/github/watabee/testfixturessample/data/Simpsons.java
public class Simpsons {
    private Simpsons() {
    }

    public static final Person HOMER = new Person("Homer", "Simpson");
}
```

これでテストフィクスチャの作成が完了したので、これを使うための設定を行います。例えば `app` モジュールでこのテストフィクスチャを使ってテストを書く場合を考えます。`app` モジュールの `build.gradle` で以下の設定を記述します。

```groovy:app/build.gradle
dependencies {
    ...
    
    testImplementation testFixtures(project(':data'))
}
```

これで `app` モジュール内のテストコードで、先ほど作成したテストフィクスチャを使用することができます。

```kotlin:app/src/test/java/com/github/watabee/testfixturessample/ExampleUnitTest.kt
@Test
fun test_homer() {
    val homer = Simpsons.HOMER // data モジュールで作成したテストフィクスチャを参照.
    assertEquals("Homer", homer.firstName)
    assertEquals("Simpson", homer.lastName)
}
```

※ Android Gradle Plugin 7.1 だと Android Studio 上でテストフィクスチャである `Simpsons` が参照できずにエラー表示になりましたが、実行は問題なくできました。 Android Gradle Plugin 7.2.0-beta02 ではエラー表示にならずに問題なく参照ができました。

# Java モジュールでのテストフィクスチャの設定

Android のライブラリモジュールではなく、Android フレームワークを含まない Java（もしくは Kotlin）モジュールでもテストフィクスチャを提供することができます。

仮にこのモジュールを `test-utils` とします。まずは `build.gradle` で `java-test-fixtures` プラグインを追加します。

```groovy:test-utils/build.gradle
plugins {
    id 'kotlin'
    id 'java-test-fixtures'
}
```

次に先ほどの Android ライブラリのモジュールと同じように `src/testFixtures/java` ディレクトリを作成し、この中にテストフィクスチャのファイルを定義します。Android ライブラリのモジュールだと Java ファイルしかサポートされていませんでしたが、私が試したところではこの場合だと Kotlin ファイルでも作成することができました。

ここでは以下のように `Date` を作成するためのユーティリティメソッドを定義してみます。

```kotlin:test-utils/src/testFixtures/java/com/github/watabee/testfixturessample/testutils/TestUtils.kt
object TestUtils {

    fun createDate(
        year: Int,
        month: Int,
        day: Int,
        hour: Int = 0,
        minute: Int = 0,
        second: Int = 0,
        millisecond: Int = 0,
        timeZone: TimeZone = TimeZone.getDefault()
    ): Date {
        val calendar = Calendar.getInstance(timeZone)
        calendar.set(year, month - 1, day, hour, minute, second)
        calendar.set(Calendar.MILLISECOND, millisecond)
        return calendar.time
    }
}
```

そして `app` モジュールでこのテストフィクスチャを使用するための設定を行います。

```groovy:app/build.gradle
dependencies {
    ...
    
    testImplementation testFixtures(project(':test-utils'))
}
```

先ほどと同様、これで `app` モジュール内のテストコードで作成したテストフィクスチャを使用することができます。

```kotlin:app/src/test/java/com/github/watabee/testfixturessample/ExampleUnitTest.kt
@Test
fun test_date() {
    val date = TestUtils.createDate(2022, 1, 1, timeZone = TimeZone.getTimeZone("Asia/Tokyo")).time
    assertEquals(1640962800000L, date)
}
```

# その他

以下の設定を追加することで、Android Lint でテストフィクスチャのコードを無視することができるようです。

```groovy
android {
    lint {
        ignoreTestFixturesSources true
    }
}
```

また、以下の設定を追加することによって Android リソースのファイルも参照することができるとドキュメントに記載されていました。

```groovy
android {
    testFixtures {
        enable true

        // enable testFixtures's android resources (disabled by default)
        androidResources true
    }
}
```

`src/testFixtures/res` 配下に `values/strings.xml` を作成して試してみましたが、私が確認した限りではテストコード内でテストフィクスチャのリソースを参照することができませんでした...

この辺りについて知見がある方がいらっしゃったらコメントをいただけるとありがたいです...！

# 参考

- https://developer.android.com/studio/preview/features#test-fixtures
- https://docs.gradle.org/current/userguide/java_testing.html#sec:java_test_fixtures
- https://issuetracker.google.com/issues/139438142