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 层次结构,而不适用于应用的其余部分。
禁用自动同步
当您通过 ComposeTestRule
(例如 assertExists()
)调用断言或操作时,您的测试会与 Compose UI 同步。在某些情况下,您可能希望停止此同步并自行控制时钟。例如,您可以控制时间以在 UI 仍然繁忙的某个时间点拍摄动画的准确屏幕截图。要禁用自动同步,请将 mainClock
中的 autoAdvance
属性设置为 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 旨在用于基于 View 的 UI,但 Espresso 知识对于 Compose 测试的某些方面仍然很有帮助。