1. Compose 测试夹具概述
1.1 测试夹具(Test Fixture)定义
测试夹具是测试执行前所需的固定环境与状态的总和。在传统单元测试中,夹具表现为 @Before / @After 方法、模拟对象、数据库连接或文件系统目录。在 Compose UI 测试中,夹具的核心是 可组合函数(Composable)的宿主环境——包括 ComposeTestRule、Activity 容器、主题、语义树等基础设施。
核心认知:Compose 测试夹具不是简单的“数据准备”,而是为声明式 UI 提供完整的运行时沙箱,使每次测试都在隔离的、可预测的 Compose 环境中执行。
1.2 Compose UI 测试的特殊性
与传统 View 体系 UI 测试相比,Compose UI 测试有三大根本差异:
| 维度 | 传统 View 测试 | Compose UI 测试 |
|---|---|---|
| 组件树构建 | 依赖 Activity/Fragment 生命周期,手动触发渲染 | 由 Compose 运行时自动重组,状态驱动渲染 |
| 交互方式 | 通过 onView() 匹配 View ID |
通过语义属性(onNodeWithText、onNodeWithTag)匹配 |
| 测试执行模型 | 同步断言,需显式 IdlingResource 处理异步 | 基于协程和快照系统,提供内置 waitForIdle() 同步点 |
| 环境依赖 | 需要完整的 Instrumentation 和 Activity 生命周期 | 可通过 createComposeRule 在轻量级宿主中运行 |
这些特殊性要求测试夹具必须为 Compose 运行时提供:重组调度器、语义树同步器、协程作用域以及快照状态容器。
1.3 夹具在测试中的角色
一个完整的 Compose UI 测试夹具承担以下职责:
- 环境初始化:创建
ComposeTestRule实例,绑定 Activity 或 ComposeHost; - 组件挂载:通过
setContent将待测 Composable 挂载到宿主树; - 依赖注入:提供 ViewModel、Repository 等模拟依赖(常与 Hilt、Koin 配合);
- 状态同步:确保 Compose 重组完成后再执行断言,避免竞态;
- 资源清理:测试结束后释放 Compose 环境,避免泄漏影响后续测试。
夹具设计原则:每个测试用例应当拥有独立的夹具实例,避免共享可变状态。推荐使用
@get:Rule 注解 ComposeTestRule,由 JUnit 规则引擎自动管理生命周期。
1.4 Compose 测试夹具架构总览
下方流程图展示了测试夹具在 Compose UI 测试中的位置及内部关键组件:
1.5 最小夹具实现示例
以下代码片段展示了一个完整的 Compose 测试夹具骨架:
import androidx.compose.ui.test.junit4.createComposeRule
import org.junit.Rule
import org.junit.Test
class CounterTest {
@get:Rule
val composeTestRule = createComposeRule()
@Test
fun testCounterIncrement() {
// 夹具:通过 setContent 挂载待测 Composable
composeTestRule.setContent {
Counter() // 假设已定义的 Composable
}
// 夹具同步等待重组完成
composeTestRule.waitForIdle()
// 断言:通过语义树验证状态
composeTestRule
.onNodeWithText("Count: 0")
.assertExists()
}
}
常见陷阱:
• 不要在
• 务必使用
• 每个测试类应只使用一个
• 不要在
setContent 外创建与 Compose 状态绑定的变量,否则会导致重组不同步;• 务必使用
waitForIdle() 或 awaitIdle() 等待重组完成,否则断言可能跑在中间态;• 每个测试类应只使用一个
@get:Rule 注解的 ComposeTestRule,避免规则冲突。