Paparazzi 库详解:介绍、集成与特点对比
先聊聊 Paparazzi 是什么
说实话,我第一次接触 Paparazzi 的时候,也被它名字唬住了——还以为是什么狗仔队工具。实际上它就是 Google 开源的一个截图测试库,专门给 Android 用,尤其适合 Compose。它的核心思路很简单:把你的 UI 在 JVM 上渲染成图片,然后跟之前保存的基准快照做对比。
我个人的理解是——它跳过了模拟器和真机,直接在开发机里完成截图。怎么做到的?靠的是 Layoutlib,也就是 Android Studio 预览那个引擎。所以跑一次测试,几秒就能拿到对比结果。嗯,这一点对 CI 来说特别友好。
集成步骤,我踩过的坑
集成 Paparazzi 其实不复杂,但有些细节容易翻车。我直接贴配置步骤,顺便说说我当初遇到的。
第一步:添加插件和依赖
在项目的 build.gradle.kts(根级别)里加插件:
plugins {
id("app.cash.paparazzi") version "1.3.1" apply false
}
然后在 app 模块里:
plugins {
id("app.cash.paparazzi")
}
dependencies {
// 如果是 Compose,需要额外加:
testImplementation("app.cash.paparazzi:paparazzi:1.3.1")
testImplementation("androidx.compose.ui:ui-test-junit4:1.5.0")
}
我曾经踩过的一个坑:忘记把 paparazzi 插件加到 app 模块,结果测试跑起来报错说找不到 snapshot 目录。后来读文档才发现插件和依赖都得配齐。
第二步:写测试类
创建一个测试类,用 @RunWith(PaparazziTestRunner::class) 注解,然后写个测试方法,把 Composable 传给 paparazzi.snapshot():
@RunWith(PaparazziTestRunner::class)
class MyComposableTest {
@get:Rule
val paparazzi = Paparazzi()
@Test
fun testButtonSnapshot() {
paparazzi.snapshot {
MyButton(text = "点击我")
}
}
}
跑测试时,Paparazzi 会自动生成一张 PNG 放在 src/test/snapshots/images/ 下。第一次跑是创建基准快照,后续跑就是做对比。
snapshots 目录加进 .gitignore,结果 CI 上每次都是新截图,对比永远失败。千万别这么干。
跟其他截图方案比,它好在哪?
现在市面上截图测试方案不少:Robolectric + 手动截图、Compose 自带的 captureToImage()、还有 Firebase Test Lab 的截图。我简单列个对比表格,这样更直观。
| 特性 | Paparazzi | Robolectric + Screenshot | Compose captureToImage | 真机截图 (Firebase) |
|---|---|---|---|---|
| 运行环境 | JVM (无需模拟器) | JVM (需 Robolectric 阴影) | Android 设备/模拟器 | 真机集群 |
| 渲染引擎 | Layoutlib (同预览) | Robolectric 自定义 | Compose 运行时 | 真机 GPU |
| 速度 | 极快(秒级) | 快(但需 Shader 编译) | 较慢(需部署到设备) | 慢(排队 + 启动) |
| 像素级对比 | 内置 | 需额外库 | 需手写 | 需第三方服务 |
| Compose 支持 | 原生 | 需额外配置 | 原生 | 原生 |
| CI 友好度 | ★★★★★ | ★★★★ | ★★ | ★★★ |
我个人的经验是:如果你的项目主要用 Compose,而且团队希望 CI 快速反馈,Paparazzi 几乎是首选。我见过有人用 Robolectric 做截图,结果因为阴影问题和真实渲染差距大,经常出现「英雄时刻」——本地跑通过,CI 上对比失败,折腾半天发现是 Robolectric 的字体渲染跟真机不一样。
工作流程一览
下面这张图是我自己画的流程图,把 Paparazzi 从编写测试到出结果的过程串了一遍——
整个流程走下来,你会发现在开发阶段「编写 → 运行 → 对比」的反馈非常快。我习惯每次写新组件时先跑一次测试生成基准图,后面修改后对比出差异,一眼就能看出哪里变了。
需要留意的几个细节
- 主题和资源问题:Paparazzi 默认使用应用的
Theme.Material3.Light,如果你用了自定义主题或者深色模式,记得在测试里手动设置。我有一次就因为这个,截图全是亮色主题,跟基准不一致。 - 动画和异步:Paparazzi 不会执行动画帧,所以
animateFloatAsState之类的效果默认是初始状态。如果需要特定状态,可以配合ComposeTestRule手动设置。 - 字体差异:JVM 上用的系统字体跟你模拟器/真机可能不同,尤其是在 CI 服务器上。我建议在测试里显式指定 Roboto 或 Noto 等常见字体,避免跨平台差异。
recordMode。我见过团队不小心把 recordMode = true 提交到 Git,结果每次 CI 跑都是重新记录基准,永远不会报失败——等于测试白写了。正确做法:本地开发用 record 生成基准,CI 用默认的对比模式。
总结一句话
Paparazzi 的核心价值在于「快」和「准」。快是指不依赖模拟器,几秒出结果;准是指用 Layoutlib 渲染,跟 IDE 预览一致。如果你正在为 Compose 项目寻找截图测试方案,我个人强烈建议从 Paparazzi 开始。它在 CI 上的表现,能让你省下不少排查时间。