Compose テストは、デフォルトで UI と同期されます。ComposeTestRule を使用して
アサーションまたはアクションを呼び出すと、テストは事前に同期され
、UI ツリーがアイドル状態になるのを待機します。
通常は、何もする必要はありません。ただし、知っておくべきエッジケースがいくつかあります。
テストが同期されると、Compose アプリは仮想クロックを使用して時間を進めます。つまり、Compose テストはリアルタイムで実行されないため、可能な限り早く結果を出すことができます。
ただし、テストを同期するメソッドを使用しなかった場合は、再コンポジションが発生せず、UI が一時停止しているように見えます。
@Test
fun counterTest() {
val myCounter = mutableStateOf(0) // State that can cause recompositions.
var lastSeenValue = 0 // Used to track recompositions.
composeTestRule.setContent {
Text(myCounter.value.toString())
lastSeenValue = myCounter.value
}
myCounter.value = 1 // The state changes, but there is no recomposition.
// Fails because nothing triggered a recomposition.
assertTrue(lastSeenValue == 1)
// Passes because the assertion triggers recomposition.
composeTestRule.onNodeWithText("1").assertExists()
}この要件が適用されるのは Compose 階層のみで、アプリの他の部分は適用対象外であることに注意してください。
自動同期を無効にする
assertExists() などの ComposeTestRule を介してアサーションまたはアクションを呼び出すと、テストは Compose UI と同期されます。場合によっては、この同期を停止して、手動でクロックを制御できます。たとえば、UI がまだビジー状態である時点で、アニメーションの正確なスクリーンショットを撮る時間を制御できます。自動同期を無効にするには、mainClock の autoAdvance プロパティを false に設定します。
composeTestRule.mainClock.autoAdvance = false
この場合、通常は手動で時間を進めます。advanceTimeByFrame() を使用してフレームを正確に 1 つだけ進めたり、advanceTimeBy() を使用して進める時間を指定したりできます。
composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)
アイドル状態のリソース
Compose は、テストと UI を同期することにより、すべてのアクションとアサーションがアイドル状態で実行され、必要に応じてクロックを待機させるか進めるようにすることができます。ただし、結果が UI 状態に影響する一部の非同期オペレーションは、テストによって認識されていないときにバックグラウンドで実行される可能性があります。
このようなアイドリング リソース をテスト内で作成して登録すると、テスト対象のアプリがビジー状態かアイドル状態かを判断する際に、それらのリソースが考慮されます。Espresso または Compose と同期されないバックグラウンド ジョブを実行する場合など、追加のアイドリング リソースを登録する必要がない場合は、何もする必要はありません。
この API は Espresso のアイドリング リソースとよく似ており、テスト対象がアイドル状態かビジー状態かを示します。Compose
テストルールを使用して、
IdlingResource の実装を登録します。
composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)
手動同期
特定のケースでは、Compose UI をテストの他の部分またはテスト対象のアプリと同期する必要があります。
waitForIdle() 関数は Compose がアイドル状態になるのを待機しますが、この関数
は autoAdvance プロパティに依存します。
composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.
composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.
どちらの場合も、waitForIdle() は保留中の 描画パスとレイアウトパス
も待機します。
また、特定の条件が満たされるまでクロックを進めることもできます。
advanceTimeUntil()
composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }
指定された条件は、このクロックの影響を受ける可能性のある状態(Compose 状態でのみ機能します)を確認する必要があります。
条件を待機する
データ読み込みや Android の
測定または描画(つまり、Compose の外部の測定または描画)など、外部の処理に依存する条件では、
より一般的なコンセプトとして waitUntil() を使用する必要があります。
composeTestRule.waitUntil(timeoutMs) { condition }
composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)
composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)
composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)
composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)
参考情報
- Android でアプリをテストする: Android テストのメイン ランディング ページで、テストの基礎と手法についてより広範な視点から説明しています。
- テストの基礎: Android アプリのテストの背景にある基本概念について詳しく学べます。
- ローカルテスト: 一部のテストは、独自のワークステーションで ローカルに実行できます。
- インストルメンテーション テスト: インストルメンテーション テストも実行することをおすすめします。つまり、デバイス上で直接実行されるテストです。
- 継続的インテグレーション: 継続的インテグレーションを使用すると、テストをデプロイ パイプラインに統合できます。
- さまざまな画面サイズをテストする: ユーザーが利用できるデバイスは多岐にわたるため、さまざまな画面サイズでテストする必要があります。
- Espresso: ビューベースの UI を対象としていますが、Espresso の知識は Compose テストのいくつかの側面で役立ちます。