테스트 동기화

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가 계속 사용 중일 때 애니메이션의 정확한 스크린샷을 캡처하는 시간을 제어할 수 있습니다. 자동 동기화를 사용 중지하려면 mainClockautoAdvance 속성을 false로 설정하세요.

composeTestRule.mainClock.autoAdvance = false

일반적으로 그런 다음에 직접 시간을 앞당깁니다. advanceTimeByFrame()을 사용하여 정확히 한 프레임을 앞당기거나 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 }

waitUntil 도우미를 사용할 수도 있습니다.

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

추가 리소스

  • Android에서 앱 테스트: 기본 Android 테스트 방문 페이지에서는 테스트 기본 사항 및 기법을 보다 폭넓은 시각으로 확인할 수 있습니다.
  • 테스트 기본 요소: Android 앱 테스트의 핵심 개념을 자세히 알아보세요.
  • 로컬 테스트: 일부 테스트는 자체 워크스테이션에서 로컬로 실행할 수 있습니다.
  • 계측 테스트: 계측 테스트도 실행하는 것이 좋습니다. 즉, 기기에서 직접 실행되는 테스트입니다.
  • 지속적 통합: 지속적 통합을 사용하면 테스트를 배포 파이프라인에 통합할 수 있습니다.
  • 다양한 화면 크기 테스트: 사용자가 사용할 수 있는 기기가 많으므로 다양한 화면 크기를 테스트해야 합니다.
  • Espresso: Espresso 지식은 뷰 기반 UI용이지만 Compose 테스트의 일부 측면에는 여전히 유용할 수 있습니다.