テスト API

UI 要素を操作するには、主に次の 3 つの方法があります。

  • ファインダーを使用すると、1 つ以上の要素(セマンティクス ツリーのノード)を選択して、アサーションの実行やアクションの実行ができます。
  • アサーションにより、要素が存在することや特定の属性を持つことを確認する。
  • アクションにより、要素に対するクリックやジェスチャーなどのユーザー イベントをシミュレートする。

これらの API の一部は、SemanticsMatcher を使用して、セマンティクス ツリーの 1 つ以上のノードを参照できます。

ファインダー

onNodeonAllNodes を使用して 1 つまたは複数のノードをそれぞれ選択できますが、onNodeWithTextonNodeWithContentDescription などの最も一般的な検索には、コンビニエンス ファインダーを使用することもできます。完全なリストは、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'

マージされていないツリーのノードと一致させる必要がある場合は、useUnmergedTreetrue に設定します。

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"))

また、assertExistsassertIsDisplayedassertTextEquals などの最も一般的なアサーションには、便利な関数を使用することもできます。完全なリストは、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 のテストのいくつかの側面においても役立ちます。