Android Compose:测试PagerState的animateScrollToPage遇异常如何解决?
解决Accompanist Pager animateScrollToPage测试时的MonotonicFrameClock异常
问题根源
animateScrollToPage是依赖MonotonicFrameClock逐帧驱动的挂起函数,而Compose测试环境的默认协程上下文并不自带这个时钟。你之前用rememberCoroutineScope拿到的协程上下文仅绑定Compose运行时,但在runOnIdle中启动协程时,上下文丢失了FrameClock,导致异常抛出。
解决方案
以下两种方法都能解决这个问题,任选其一即可:
方法一:使用TestFrameClock手动驱动动画
import kotlinx.coroutines.test.TestFrameClock import kotlinx.coroutines.runBlocking // 初始化测试用帧时钟 val testClock = TestFrameClock() composeTestRule.setContent { // 给CoroutineScope注入测试帧时钟 val scope = rememberCoroutineScope { testClock + it.coroutineContext } val pagerState = rememberPagerState() // 渲染Pager组件... } composeTestRule.runOnIdle { runBlocking(testClock) { // 启动动画 scope.launch { pagerState.animateScrollToPage(page = 8) } // 推进时钟,给动画足够时间完成(比如1秒) testClock.advanceTimeBy(1000) } // 执行断言 assertThat(pagerState.currentPage).isEqualTo(8) assertThat(pagerState.pageCount).isEqualTo(10) }
方法二:利用Compose测试库自带的mainClock
composeTestRule.setContent { val pagerState = rememberPagerState() // 渲染Pager组件... } composeTestRule.runOnIdle { // 关闭自动时钟推进,手动控制动画进度 composeTestRule.mainClock.autoAdvance = false runBlocking { // 启动动画 launch { pagerState.animateScrollToPage(page = 8) } // 推进时钟至动画完成 composeTestRule.mainClock.advanceTimeBy(1000) } // 执行断言 assertThat(pagerState.currentPage).isEqualTo(8) assertThat(pagerState.pageCount).isEqualTo(10) }
关键注意事项
- 必须确保动画完全执行完毕后再断言,否则
currentPage可能处于中间状态导致断言失败,所以要推进足够的时间(一般1秒足够覆盖Pager动画)。 - 不要在
runOnIdle中直接使用rememberCoroutineScope的协程启动动画,因为该上下文无法在测试环境中获取到FrameClock。
内容的提问来源于stack exchange,提问作者testivanivan
相关产品推荐
相关产品推荐

