Android 分层测试策略
Android 分层测试策略
测试的目标不是追求用例数量,而是用合适成本发现高风险问题。所有逻辑都依赖真机界面测试,会执行缓慢且定位困难;只写纯单元测试,又覆盖不了数据库、生命周期和系统交互。分层测试通过不同范围的测试形成互补。
一、划分测试层级
可以把常见测试分为:
- 单元测试:验证纯业务规则、状态转换和数据映射。
- 组件测试:验证数据库、仓库或自定义控件的局部集成。
- 页面测试:验证主要界面状态与用户操作。
- 端到端测试:覆盖少量关键业务链路。
越靠近端到端,环境更真实但执行更慢。稳定业务规则应尽量下沉到快速测试中。
二、让业务逻辑脱离 Android 环境
class CalculateFeeUseCase(
private val rule: FeeRule
) {
operator fun invoke(amountInCent: Long): FeeResult {
require(amountInCent >= 0)
return rule.calculate(amountInCent)
}
}
这种纯 Kotlin 类无需设备即可测试,失败时原因直接。页面只负责收集输入、调用用例和渲染结果。
三、使用小接口隔离外部依赖
interface OrderRepository {
suspend fun submit(command: SubmitOrderCommand): SubmitOrderResult
}
class FakeOrderRepository : OrderRepository {
var nextResult: SubmitOrderResult = SubmitOrderResult.Success
val commands = mutableListOf<SubmitOrderCommand>()
override suspend fun submit(
command: SubmitOrderCommand
): SubmitOrderResult {
commands += command
return nextResult
}
}
Fake 同时提供可控结果和调用记录,不需要真实网络。接口只包含被测逻辑需要的能力,避免为测试实现庞大基础客户端。
四、测试 ViewModel 状态
@Test
fun submitSuccess_updatesState() = runTest {
val repository = FakeOrderRepository()
val viewModel = OrderViewModel(repository)
viewModel.submit(validCommand)
advanceUntilIdle()
assertEquals(OrderUiState.Success, viewModel.uiState.value)
assertEquals(listOf(validCommand), repository.commands)
}
协程测试使用可控制调度器,不应通过真实等待猜测任务何时完成。项目如果封装了调度器提供者,应在测试中注入。
五、覆盖失败与取消
异步测试不能只验证成功。至少包括:
- 可重试错误与永久错误映射。
- 新请求开始时旧请求取消。
- 取消不显示普通失败提示。
- 重复点击只提交一次。
- 页面销毁后不再更新视图。
可暂停 Fake 可以由测试主动控制请求完成顺序,稳定复现竞态。
六、数据库测试关注真实行为
DAO 查询、事务和迁移依赖数据库行为,适合使用受控测试数据库验证。测试数据保持最小,只构造能证明排序、筛选和回滚的记录。
迁移测试应从真实历史结构生成旧库,再升级到当前版本。直接创建最新版数据库无法证明迁移语句正确。
七、界面测试围绕用户结果
页面测试应点击可见控件并断言最终界面,不依赖内部私有字段。控件需要稳定语义和测试标识,但不应把动态列表位置当作永久业务标识。
关键场景包括加载、内容、空状态、错误重试和旋转恢复。视觉样式可以由截图测试辅助,但仍需文本和交互断言。
八、避免共享可变测试环境
测试之间共享单例、数据库或账户状态,会造成顺序依赖。每个测试应准备自己的输入,并在结束后精确清理所创建资源。
固定当前时间、随机标识和调度器,可以让边界行为可重复。只抽象确实影响确定性的系统能力,不必为了测试包装所有类。
九、测试命名描述行为
名称应包含前置条件、动作和结果,例如“余额不足时提交返回业务失败”。测试体遵循准备、执行、断言的清晰结构,让失败报告本身能够说明问题。
一个测试聚焦一个主要行为。过多无关断言会让任一小改动破坏整组用例。
十、选择回归重点
高价值测试通常覆盖:
- 金额、权限和状态机等高风险规则。
- 曾经出现过的缺陷路径。
- 模块之间稳定契约。
- 数据迁移和兼容边界。
- 核心用户链路。
简单属性赋值和框架已经保证的行为无需重复测试。
总结
Android 测试应把大部分业务规则放在快速单元测试中,用组件测试验证数据库和框架边界,再以少量页面及端到端测试覆盖真实链路。通过可控依赖、虚拟时间和明确状态断言,测试才能稳定、快速,并真正帮助定位问题。
- 点赞
- 收藏
- 关注作者
评论(0)