同步测试

默认情况下,Compose 测试会与界面同步。当您使用 ComposeTestRule 调用断言或操作时,测试会预先同步,直到界面树处于空闲状态。

通常,您无需执行任何操作。但是,您应该了解一些极端情况。

同步测试时,您可以使用虚拟时钟将 Compose 应用的时间提前。这意味着 Compose 测试不会实时运行,从而能够尽快通过测试。

但是,如果您不使用同步测试的方法,则不会发生任何重组,并且界面会暂停。

@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 界面同步。在某些情况下,您可能需要停止此同步并自行控制时钟。例如,您可以控制时间,以便在界面仍处于繁忙状态时对动画进行精确截图。如需停用自动同步功能,请将 mainClock 中的 autoAdvance 属性设置为 false

composeTestRule.mainClock.autoAdvance = false

一般情况下,您需要自行将时间提前。您可以使用 advanceTimeByFrame() 仅提前一帧,或使用 advanceTimeBy() 提前一段特定时间:

composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)

空闲资源

Compose 可以同步测试和界面,以便以空闲状态完成各项操作和断言,从而根据需要等待或将时钟提前。但是,某些影响界面状态的异步操作可在后台运行,而测试无法得知这些结果。

在测试中创建并注册这些空闲资源,以便在确定被测应用是忙碌还是空闲时将其纳入考虑范围。您不必采取任何措施,除非您需要注册其他空闲资源(例如,当您运行未与 Espresso 或 Compose 同步的后台作业时)。

此 API 与 Espresso 的空闲资源非常相似,用于指示受测对象是空闲还是忙碌。使用 Compose 测试规则注册 IdlingResource 的实现。

composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)

手动同步

在某些情况下,您必须将 Compose 界面与测试的其他部分或您测试的应用同步。

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:虽然适用于基于 View 的界面,但掌握 Espresso 对 Compose 测试的某些方面仍然很有帮助。