一般的なパターン

確立されたアプローチとパターンで Compose アプリをテストできます。

単独でのテスト

ComposeTestRule を使用すると、任意のコンポーザブル(アプリ全体、単一画面、小さな要素)を表示するアクティビティを開始できます。また、コンポーザブルが正しくカプセル化され、独立して動作していることを確認することもおすすめします。これにより、より簡単で焦点を絞った UI テストが可能になります。

これは、単体 UI テストのみを作成するということではありません。UI テストでは、UI の大きな部分にスコープ設定することも非常に重要です。

独自のコンテンツの設定後にアクティビティとリソースにアクセスする

多くの場合、composeTestRule.setContent を使用してテスト対象のコンテンツを設定し、アクティビティ リソースへのアクセスも必要になります(表示されるテキストが文字列リソースと一致することをアサートする場合など)。ただし、createAndroidComposeRule() で作成されたルールに対して、アクティビティがすでに setContent を呼び出している場合、そのルールを呼び出すことはできません。

これを実現する一般的なパターンは、ComponentActivity などの空のアクティビティを使用して AndroidComposeTestRule を作成することです。

class MyComposeTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

アプリの AndroidManifest.xml ファイルに ComponentActivity を追加する必要があるのでご注意ください。これを有効にするには、この依存関係をモジュールに追加します。

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

カスタム セマンティクス プロパティ

カスタム セマンティクス プロパティを作成して、情報をテストに公開できます。これを行うには、新しい SemanticsPropertyKey を定義し、SemanticsPropertyReceiver を使用して使用できるようにします。

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

次に、このプロパティを semantics 修飾子で使用します。

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

テストから、SemanticsMatcher.expectValue を使用してプロパティの値をアサートします。

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

状態の復元を検証する

アクティビティまたはプロセスを再作成したときに、Compose 要素の状態が正しく復元されることを確認します。このようなチェックは、StateRestorationTester クラスを使用して、アクティビティの再作成に依存せずに実行します。

このクラスを使用すると、コンポーザブルの再作成をシミュレートできます。特に、rememberSaveable の実装の検証が役立ちます。


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

さまざまなデバイス設定をテストする

Android アプリは、ウィンドウ サイズ、ロケール、フォントサイズ、ダークモードとライトモードなど、さまざまな状況の変化に適応する必要があります。これらの条件のほとんどは、ユーザーが制御するデバイスレベルの値から導出され、現在の Configuration インスタンスで公開されます。テストではデバイスレベルのプロパティを構成する必要があるため、テストでさまざまな構成を直接テストすることは困難です。

DeviceConfigurationOverride は、テスト対象の @Composable コンテンツについて、さまざまなデバイス構成をローカライズされた方法でシミュレートできるテスト専用の API です。

DeviceConfigurationOverride のコンパニオン オブジェクトには、デバイスレベルの設定プロパティをオーバーライドする次の拡張関数があります。

特定のオーバーライドを適用するには、DeviceConfigurationOverride() トップレベル関数の呼び出しでテスト対象コンテンツをラップし、パラメータとして適用するオーバーライドを渡します。

たとえば、次のコードは、DeviceConfigurationOverride.ForcedSize() オーバーライドを適用してローカルで密度を変更し、テストを実行するデバイスがそのウィンドウ サイズを直接サポートしていない場合でも、MyScreen コンポーザブルを大きな横向きウィンドウでレンダリングします。

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // will be rendered in the space for 1280dp by 800dp without clipping
    }
}

複数のオーバーライドをまとめて適用するには、DeviceConfigurationOverride.then() を使用します。

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

その他のリソース

  • Android でアプリをテストする: Android テストのメイン ランディング ページでは、テストの基礎と手法について幅広く確認できます。
  • テストの基礎: Android アプリのテストの基本コンセプトについて説明します。
  • ローカルテスト: 一部のテストは、自分のワークステーションでローカルに実行できます。
  • インストルメンテーション テスト: インストルメンテーション テストも実行することをおすすめします。つまり、デバイス上で直接実行されるテストです。
  • 継続的インテグレーション: 継続的インテグレーションを使用すると、テストをデプロイ パイプラインに統合できます。
  • さまざまな画面サイズをテストする: ユーザーが利用できるデバイスが多数ある場合は、さまざまな画面サイズでテストする必要があります。
  • Espresso: Espresso の知識はビューベースの UI を対象としていますが、Compose テストの一部では Espresso の知識が役立ちます。