UI 要素に対して行う操作は主に 3 つあります。
- ファインダーを使用すると、1 つまたは複数の要素(セマンティクス ツリーのノード)を選択して、アサーションの実行やアクションの実行を行うことができます。
- アサーションにより、要素が存在することや特定の属性を持つことを確認する。
- アクションにより、要素に対するクリックやジェスチャーなどのユーザー イベントをシミュレートする。
これらの API の一部は、SemanticsMatcher
に対応していて、セマンティクス ツリーの 1 つ以上のノードを参照できます。
ファインダー
onNode
と onAllNodes
を使用して、それぞれ 1 つまたは複数のノードを選択できますが、onNodeWithText
や onNodeWithContentDescription
などの便利なファインダーを使用して一般的な検索を行うこともできます。完全なリストについては、Compose テスト クイック リファレンスをご覧ください。
ノードを 1 つ選択する
composeTestRule.onNode(<<SemanticsMatcher>>, useUnmergedTree = false): SemanticsNodeInteraction
// Example
composeTestRule
.onNode(hasText("Button")) // Equivalent to onNodeWithText("Button")
ノードを複数選択する
composeTestRule
.onAllNodes(<<SemanticsMatcher>>): SemanticsNodeInteractionCollection
// Example
composeTestRule
.onAllNodes(hasText("Button")) // Equivalent to onAllNodesWithText("Button")
マージされていないツリー
一部のノードでは、子のセマンティクス情報がマージされます。たとえば、2 つのテキスト要素を含むボタンでは、テキスト要素のラベルがマージされます。
MyButton {
Text("Hello")
Text("World")
}
テストから、printToLog()
を使用してセマンティクス ツリーを表示します。
composeTestRule.onRoot().printToLog("TAG")
このコードでは、次の出力が表示されます。
Node #1 at (...)px
|-Node #2 at (...)px
Role = 'Button'
Text = '[Hello, World]'
Actions = [OnClick, GetTextLayoutResult]
MergeDescendants = 'true'
マージされていないツリーのノードと一致させる必要がある場合は、useUnmergedTree
を true
に設定します。
composeTestRule.onRoot(useUnmergedTree = true).printToLog("TAG")
このコードでは、次の出力が表示されます。
Node #1 at (...)px
|-Node #2 at (...)px
OnClick = '...'
MergeDescendants = 'true'
|-Node #3 at (...)px
| Text = '[Hello]'
|-Node #5 at (83.0, 86.0, 191.0, 135.0)px
Text = '[World]'
useUnmergedTree
パラメータはすべてのファインダーで使用できます。たとえば、ここでは onNodeWithText
ファインダーで使用されています。
composeTestRule
.onNodeWithText("World", useUnmergedTree = true).assertIsDisplayed()
アサーション
1 つ以上のマッチャーを使用して、ファインダーで返される SemanticsNodeInteraction
に対して assert()
を呼び出すことで、アサーションを確認します。
// Single matcher:
composeTestRule
.onNode(matcher)
.assert(hasText("Button")) // hasText is a SemanticsMatcher
// Multiple matchers can use and / or
composeTestRule
.onNode(matcher).assert(hasText("Button") or hasText("Button2"))
また、assertExists
、assertIsDisplayed
、assertTextEquals
などの最も一般的なアサーションには、便利な関数を使用することもできます。完全なリストは、Compose テストのクイック リファレンスをご覧ください。
ノードのコレクションでアサーションを確認する関数もあります。
// Check number of matched nodes
composeTestRule
.onAllNodesWithContentDescription("Beatle").assertCountEquals(4)
// At least one matches
composeTestRule
.onAllNodesWithContentDescription("Beatle").assertAny(hasTestTag("Drummer"))
// All of them match
composeTestRule
.onAllNodesWithContentDescription("Beatle").assertAll(hasClickAction())
アクション
ノードにアクションを挿入するには、perform…()
関数を呼び出します。
composeTestRule.onNode(...).performClick()
アクションの例を次に示します。
performClick(),
performSemanticsAction(key),
performKeyPress(keyEvent),
performGesture { swipeLeft() }
完全なリストについては、Compose テスト クイック リファレンスをご覧ください。
マッチャー
Compose コードのテストには、さまざまなマッチャーを使用できます。
階層マッチャー
階層マッチャーを使用すると、セマンティクス ツリーを上下に移動して、マッチングを実施できます。
fun hasParent(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnySibling(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyAncestor(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyDescendant(matcher: SemanticsMatcher): SemanticsMatcher
こうしたマッチャーの例を次に示します。
composeTestRule.onNode(hasParent(hasText("Button")))
.assertIsDisplayed()
セレクタ
テストを作成する別の方法として、セレクタを使用する方法があります。これにより、一部のテストが読みやすくなります。
composeTestRule.onNode(hasTestTag("Players"))
.onChildren()
.filter(hasClickAction())
.assertCountEquals(4)
.onFirst()
.assert(hasText("John"))
完全なリストは、Compose テストのクイック リファレンスをご覧ください。
参考情報
- Android でアプリをテストする: Android テストのメイン ランディング ページでは、テストの基礎と手法について幅広く説明しています。
- テストの基礎: Android アプリのテストの基本コンセプトについて学びます。
- ローカルテスト: 一部のテストは、自分のワークステーションでローカルに実行できます。
- インストルメンテーション テスト: インストルメンテーション テストも実行することをおすすめします。つまり、デバイス上で直接実行されるテストです。
- 継続的インテグレーション: 継続的インテグレーションを使用すると、テストをデプロイ パイプラインに統合できます。
- さまざまな画面サイズをテストする: ユーザーが利用できるデバイスは非常に多様であるため、さまざまな画面サイズでテストする必要があります。
- Espresso: Espresso はビューベースの UI を対象としていますが、Compose テストの一部のアスペクトでも役立ちます。