您可以使用成熟的方法和模式测试 Compose 应用。
单独进行测试
ComposeTestRule
可让您启动显示任何可组合项的 activity:整个应用、单个屏幕或小元素。此外,最好检查可组合项是否被正确封装以及它们是否独立工作,从而使界面测试更容易且更有针对性。
这并不意味着您应仅创建单元界面测试。范围涵盖更大一部分界面的界面测试也非常重要。
在设置自己的内容后访问 activity 和资源
通常,您需要使用 composeTestRule.setContent
设置受测内容,还需要访问 activity 资源,例如,断言显示的文本与字符串资源是否匹配。不过,如果 setContent
已被 activity 调用,则无法再对使用 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.DarkMode()
:将系统替换为深色主题或浅色主题。DeviceConfigurationOverride.FontScale()
:替换系统字体比例。DeviceConfigurationOverride.FontWeightAdjustment()
:替换系统字体粗细调整。DeviceConfigurationOverride.ForcedSize()
:无论设备尺寸如何,都强制使用特定的空间量。DeviceConfigurationOverride.LayoutDirection()
:替换布局方向(从左到右或从右到左)。DeviceConfigurationOverride.Locales()
:替换语言区域。DeviceConfigurationOverride.RoundScreen()
:如果屏幕为圆形,则替换此值。
如需应用特定替换项,请将要测试的内容封装在对 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:虽然 Espresso 适用于基于 View 的界面,但 Espresso 知识对于 Compose 测试的某些方面仍然很有帮助。