常见模式

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

单独进行测试

借助 ComposeTestRule,您可以启动显示任何可组合项的 activity:整个应用、单个屏幕或小元素。此外,最好检查可组合项是否已正确封装以及它们是否独立运行,从而实现更简单、更有针对性的界面测试。

这并不意味着您应仅创建单元界面测试。范围涵盖更大一部分界面的界面测试也非常重要。

在设置自己的内容后访问 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")

自定义语义属性

您可以创建自定义 semantics 属性来向测试提供信息。为此,请定义一个新的 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 的界面,但掌握 Espresso 对 Compose 测试的某些方面仍然很有帮助。