Android 分层测试策略

举报
shenlan9755 发表于 2026/09/21 09:30:13 2026/09/21
【摘要】 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 测试应把大部分业务规则放在快速单元测试中,用组件测试验证数据库和框架边界,再以少量页面及端到端测试覆盖真实链路。通过可控依赖、虚拟时间和明确状态断言,测试才能稳定、快速,并真正帮助定位问题。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。