테스트 API

UI 요소와 상호작용하는 방법에는 크게 세 가지가 있습니다.

  • 파인더를 사용하면 요소 (또는 시맨틱 트리의 노드)를 하나 이상 선택하여 어설션을 만들거나 작업을 실행할 수 있습니다.
  • 어설션은 요소가 있는지 또는 특정 속성을 보유하는지 확인하는 데 사용됩니다.
  • 작업은 클릭이나 기타 동작과 같은 시뮬레이션된 사용자 이벤트를 요소에 삽입합니다.

이러한 API의 일부는 시맨틱 트리에서 노드를 하나 이상 참조하는 SemanticsMatcher를 허용합니다.

파인더

onNodeonAllNodes를 사용하여 각각 노드를 하나나 여러 개 선택할 수 있지만 onNodeWithText, onNodeWithContentDescription 등 가장 일반적인 검색에 편의 파인더를 사용할 수도 있습니다. Compose 테스트 요약본에서 전체 목록을 찾아볼 수 있습니다.

단일 노드 선택

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

병합되지 않은 트리

일부 노드는 하위 요소의 시맨틱 정보를 병합합니다. 예를 들어 다음과 같이 텍스트 요소가 두 개 있는 버튼은 텍스트 요소 라벨을 병합합니다.

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

어설션

하나 이상의 매처가 있는 파인더가 반환한 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: 뷰 기반 UI용이지만 Espresso 지식은 Compose 테스트의 일부 측면에도 유용할 수 있습니다.