常见模式

您可以使用成熟的方法和模式测试您的 Compose 应用程序。

隔离测试

ComposeTestRule 允许您启动一个显示任何可组合元素的 Activity:您的完整应用程序、单个屏幕或小型元素。 作为最佳实践,还应该检查您的可组合元素是否正确封装且独立工作,从而简化和聚焦 UI 测试。

但这并不意味着您应该只创建单元 UI 测试。 作用域更大 UI 部分的 UI 测试同样非常重要。

在设置您自己的内容后访问 Activity 和资源

通常,您需要使用 composeTestRule.setContent 设置测试中的内容,并且还需要访问 Activity 资源,例如,断言显示的文本与字符串资源匹配。 但是,如果您创建的 Activity 已经调用了 setContent,则无法在使用 createAndroidComposeRule() 创建的规则上调用它。

一种常见的模式是使用空的 Activity(例如 ComponentActivity)创建 AndroidComposeTestRule

class MyComposeTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

请注意,需要将 ComponentActivity 添加到应用程序的 AndroidManifest.xml 文件中。 通过将以下依赖项添加到您的模块来启用它。

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

自定义语义属性

您可以创建自定义 语义 属性,以向测试公开信息。 为此,请定义一个新的 SemanticsPropertyKey 并使用 SemanticsPropertyReceiver 使其可用。

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

现在,在 semantics 修饰符中使用该属性。

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

在测试中,使用 SemanticsMatcher.expectValue 断言属性的值。

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

验证状态恢复

验证 Activity 或进程重新创建时 Compose 元素的状态是否被正确恢复。 使用 StateRestorationTester 类执行此类检查,而无需依赖于 Activity 重新创建。

此类允许您模拟可组合元素的重新创建。 它对于验证 rememberSaveable 的实现特别有用。


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

测试不同的设备配置

Android 应用程序需要适应许多不断变化的条件:窗口大小、语言环境、字体大小、深色和浅色主题等等。 这些条件中的大多数都源自用户控制的设备级值,并通过当前的 Configuration 实例公开。

DeviceConfigurationOverride 是一个仅限于测试的 API,它允许您以本地化的方式为测试中的 @Composable 内容模拟不同的设备配置。

DeviceConfigurationOverride 的伴随对象具有以下扩展函数,它们会覆盖设备级配置属性。

要应用特定覆盖,请将测试中的内容包装在对 DeviceConfigurationOverride() 顶级函数的调用中,并将要应用的覆盖作为参数传递。

例如,以下代码应用 DeviceConfigurationOverride.ForcedSize() 覆盖以在本地更改密度,强制 MyScreen 可组合元素以大型横向窗口呈现,即使测试运行的设备不支持该窗口大小。

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

要将多个覆盖一起应用,请使用 DeviceConfigurationOverride.then()

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

其他资源

  • 在 Android 上测试应用程序:主要的 Android 测试登陆页面提供了更广泛的测试基础知识和技术的概述。
  • 测试基础知识详细了解测试 Android 应用程序背后的核心概念。
  • 本地测试您可以在自己的工作站上本地运行一些测试。
  • 已测试的测试建议您还运行已测试的测试。 也就是说,在设备上直接运行的测试。
  • 持续集成持续集成允许您将测试集成到您的部署管道中。
  • 测试不同的屏幕尺寸由于有许多设备可供用户使用,因此您应该针对不同的屏幕尺寸进行测试。
  • Espresso:虽然旨在用于基于 View 的 UI,但 Espresso 知识对于 Compose 测试的某些方面仍然很有帮助。