작성하는 모든 테스트는 테스트 대상과 적절하게 동기화(synchronization)되어야 한다. 예를 들어 onNodeWithText와 같은 finder를 사용할 때, 테스트는 시맨틱 트리를 쿼리하기 전에 앱이 유휴 상태가 될 때까지 기다린다. 동기화가 없으면 테스트에서 표시되기 전에 요소를 찾거나 불필요하게 기다릴 수 있다.

이 단계에서는 앱을 실행할 때 다음과 같은 Overview(개요) 화면을 사용한다.

17e585f529a6d613.gif

‘Alerts’ 카드의 반복적인 깜박임 애니메이션에 주목하고, 이 요소에 주의를 기울이자.

OverviewScreenTest라는 다른 테스트 클래스를 만들고, 다음 내용을 추가하자.

class OverviewScreenTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun overviewScreen_alertsDisplayed() {
        composeTestRule.setContent {
            OverviewBody()
        }

        composeTestRule
            .onNodeWithText("Alerts")
            .assertIsDisplayed()
    }
}

만약 테스트를 실행하면, 테스트가 끝나지 않는 것을 확인할 수 있다. (30초 후에 타임아웃 된다)

880d5515b578d45e.png

에러 내용은 다음과 같다.

androidx.compose.ui.test.junit4.android.ComposeNotIdleException: Idling resource timed out: possibly due to compose being busy.
IdlingResourceRegistry has the following idling resources registered:
- [busy] androidx.compose.ui.test.junit4.android.ComposeIdlingResource@d075f91

이것은 기본적으로 컴포즈가 지속적으로 무언가 하기 때문에(busy), 앱을 테스트와 동기화]할 방법이 없다는 것을 알려준다.

이미 짐작했을 것이다. 문제는 무한으로 깜박이는 애니메이션이다. 앱이 유휴(idle) 상태가 아니므로 테스트를 계속할 수 없다.

무한 애니메이션의 구현을 살펴보자.

app/src/main/java/com/example/compose/rally/ui/overview/OverviewScreen.kt

var currentTargetElevation by remember {  mutableStateOf(1.dp) }
LaunchedEffect(Unit) {
    // Start the animation
    currentTargetElevation = 8.dp
}
val animatedElevation = animateDpAsState(
    targetValue = currentTargetElevation,
    animationSpec = tween(durationMillis = 500),
    finishedListener = {
        currentTargetElevation = if (currentTargetElevation > 4.dp) {
            1.dp
        } else {
            8.dp
        }
    }
)
Card(elevation = animatedElevation.value) { ... }

이 코드는 기본적으로 애니메이션이 완료되기를 기다리고(finishedListener) 다시 실행한다.

이 테스트를 수정하는 한 가지 방법은 개발자 옵션에서 애니메이션을 비활성화하는 것이다. 이는 View 시스템에서 이를 처리하는 널리 허용되는 방법 중 하나다.

컴포즈에서 애니메이션 API는 테스트 가능성을 염두에 두고 설계되었으므로, 올바른 API를 사용하여 문제를 해결할 수 있다. animateDpAsState 애니메이션을 다시 시작하는 대신, 무한 애니메이션을 사용할 수 있다.

무한 애니메이션은 컴포즈가테스트가 이해하는 특별한 경우이므로, 테스트를 바쁘게(busy) 유지하지 않는다.

OverviewScreen.kt에서 AlertCard 컴포저블 함수의 코드를 적절한 API로 바꿔보자.

    val infiniteElevationAnimation = rememberInfiniteTransition()
    val animatedElevation: Dp by infiniteElevationAnimation.animateValue(
        initialValue = 1.dp,
        targetValue = 8.dp,
        typeConverter = Dp.VectorConverter,
        animationSpec = infiniteRepeatable(
            animation = tween(500),
            repeatMode = RepeatMode.Reverse
        )
    )
    Card(elevation = animatedElevation) {

테스트를 실행하면 이제 통과하는 것을 확인할 수 있다.

4381509baa58644f.png

축하! 이 단계에서는 동기화와 애니메이션이 테스트에 미치는 영향에 대해 배웠다.


후원하기

카테고리: Compose

0개의 댓글

답글 남기기

Avatar placeholder

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.