Compose快照回归常见错误与解决方案教程 - 第1节

一、快照回归测试到底是什么

做 Android 开发的,特别是玩 Compose 的,一定遇到过这种情况:

某天你改了一行看似无关的代码,结果 UI 跑偏了。按钮歪了,间距没了,颜色不对。
你把它改回来?但你已经忘了原来长啥样了。

嗯,我就是被这个问题折磨过好几次,才下定决心把快照回归测试请进项目里的。

啥是快照测试?

说白了,就是给你的 UI “拍张照”。
你写了一个 Composable 组件,测试框架会把它渲染出来,截一张图保存下来。
下次再跑测试的时候,它又会截一张新图。
新旧两张图一对比,不一样的地方就会标红。

这个截图,就叫快照。
这个比对过程,就叫回归检验。

核心流程: 编写 Composable → 渲染并截图 → 与基线对比 → 检测差异 → 报告失败或通过

你可以把它理解成“版本控制给 UI 用”。
代码有 Git 管理,UI 凭什么没有?

为什么需要回归测试?

人不是机器。再厉害的工程师,改 UI 也会有疏漏。

  • 改了一个颜色值,影响了 10 个页面——你只测了首页,别的崩了。
  • 重构了布局组件——你觉得没变,但有些边距偷偷变了。
  • 第三方库升级了——默认样式变了,你根本没注意。

快照回归测试可以在你提交代码前,像哨兵一样提醒你:
“诶,这个界面和上次不一样了,你确定要改吗?”

我个人习惯: 每次 PR 前跑一遍快照测试,比肉眼审核快 10 倍。真的。

Compose 里快照测试的特殊之处

你可能做过传统的 View 系统截图测试。
但 Compose 的玩法不一样。

维度 传统 View 截图 Compose 快照
渲染方式 依赖 Activity / Fragment 纯组合函数,无需 Activity
环境依赖 需要真机或模拟器 可运行在 JVM(使用 Robolectric)
截图内容 全屏或指定 View 只截取 Composable 边界内
对比精度 像素级,易受设备影响 可配置阈值,更灵活
维护成本 高(每次设备更换都要重新截图) 低(记住基线,只在业务变化时更新)

Compose 的快照测试可以在纯 JVM 环境下跑。
不需要开模拟器。
不需要等构建。
速度快到可怕。

我记得第一次把 Compose 快照接入流水线的时候,全组都震惊了。
以前跑完整 UI 测试得十几分钟,现在几十秒搞定。

一个简洁的流程示意图

下面这张图,帮你把整件事串起来:

Compose 快照回归测试核心流程 1. 编写 Composable 2. 生成快照 3. 人工审核基线 4. 修改代码 5. 重新生成快照 6. 差异对比 ✅ 通过 → 提交 ❌ 失败 → 修复 失败后回退到第 4 步,修复后再来
你想想看,这套流程一旦跑起来,基本就是“自动化把关”。
我当年在项目里第一次跑通整条链路的时候,感觉像是请了一个永远不睡觉的 QA。

什么时候该用快照回归?

不是所有场景都适合。我遇到过有人把网络请求的结果也放进了快照里,那是胡闹。

  • 静态 UI 组件:按钮、卡片、列表项、弹窗样式——强烈推荐
  • 状态驱动的 UI:loading / error / empty / content 四种状态——非常适合
  • 主题切换组件:亮色/暗色模式——一个快照测两个风格
  • 动态内容区域:不推荐,建议用传统单元测试替代
我曾经踩过的坑: 不要对含有随机数、实时时间、网络图片 URL 的组件做快照。
每次截图都不一样,测试永远过不了。白白浪费两小时。

如何开始写第一个快照测试?

在 Compose 里,一个简单的快照测试长这样:

@Test
fun myButton_snapshot() {
    composeTestRule.setContent {
        MyButton(text = "点击我")
    }

    // 与基线对比
    composeTestRule.onRoot().captureToImage()
}

但这只是表面。真正的核心在于基线管理和差异分析。

我会在后面的章节里,一步步带着你搭一个完整的快照回归测试框架。
从选择工具库,到配置 CI 流水线,再到处理那些“老改不对”的棘手情况。

千万别跳过。这些内容都是我亲手淌过一遍的经验。

好了,第一章就说到这里。
你至少明白了什么是快照测试,为什么它重要,以及它在整个 Compose 项目里的位置。

下一件事情?
嗯,回去看看你项目里的 UI 改动频率,找一两个组件练练手。