Screenshot Test:它是什么、类型及在测试中如何工作

作者: IT Sectr 发布日期: 2026-04-10 阅读时间: 9 分钟

Screenshot Test — 通过捕获和比较应用程序屏幕截图与参考图像来自动检查用户界面。与 golden 测试不同,screenshot 测试在真实设备或模拟器上执行,捕获带有导航、系统元素和动画的完整屏幕,并使用 UI Automator (Android) 或 XCUITest (iOS) 与应用程序进行交互。更多信息 — 请参阅Android UI Automator 文档

核心要点

  • Screenshot Test — 在设备上捕获完整屏幕截图以与参考进行比较
  • UI Automator — 用于程序化捕获截图和与 UI 交互的 Android 框架
  • XCUITest — 支持 iPad、iPhone 和 Accessibility 的用于 screenshot 测试的 iOS 框架
  • Firebase Test Lab — 在多个真实设备上并行运行 screenshot 测试
  • Diff 分析 — 将截图与参考进行比较,标记变化并生成 HTML 报告

什么是 Screenshot Test?为什么需要它?

Screenshot Test — 是用户界面的端到端测试,测试打开应用程序屏幕,执行操作(点击、输入文本、滚动)并捕获所得状态的截图。截图与存储在仓库中的参考图(baseline)进行比较。如果截图不同 — 测试失败。Screenshot 测试发现单元测试中看不到的视觉回归:错误的边距、元素重叠、错误的颜色。

为什么有了 golden 测试还需要 screenshot 测试 — golden 测试单独检查组件:一个按钮、一张卡片、一段文本。Screenshot 测试在尽可能接近生产环境的情况下检查整个屏幕:真实导航、真实数据(或尽可能真实的 mock)、真实系统字体、真实状态栏。只有 screenshot 测试能显示按钮在真实设备上与其他元素重叠。

Screenshot 测试的商业价值

商业价值 — 根据 Google(2023)的数据,视觉错误占移动应用所有错误的 15-25%。Screenshot 测试自动化了以前由 QA 工程师手动执行的视觉质量检查。一个 screenshot 测试可替代 5-10 分钟的单屏幕手动测试。对于拥有 50 个屏幕的应用,节省:每次回归测试节省 4-8 人时。Screenshot 测试在 2-3 个发版周期内即可收回成本。

Screenshot Test vs Golden Test:方法比较

Golden 测试 更快更简单:在离屏缓冲区中渲染组件只需毫秒,不需要设备,在 CI 中稳定。Screenshot 测试更真实:捕获带有系统元素的真实屏幕,支持动画和导航,在真实设备上工作。选择取决于目标:为开发人员提供快速反馈(golden)或在发版前实现最大真实性(screenshot)。

特性Screenshot TestGolden Test
速度2-30 秒50-200 毫秒
真实性最大(真实设备)有限(离屏)
需要设备是(模拟器/物理设备)否(JVM、XCTest)
动画支持不支持
导航多步骤场景单个组件
Flakiness高(网络、时序)中(GPU、字体)
并行性Device Farm (Firebase、AWS)多线程 JVM/XCTest

覆盖策略:golden + screenshot

Golden + Screenshot — 对组件库(Design System)中的每个 UI 组件使用 golden 测试。80% 的视觉回归在组件层级被捕获。Screenshot 测试 — 用于关键用户路径:入门引导、登录、支付流程、购物车。20% 与组件在真实屏幕上集成相关的回归只能被 screenshot 测试捕获。在 IT Sectr,我们使用 80/20 的比例:400 golden + 100 screenshot。

什么时候不需要 screenshot 测试 — 如果屏幕由静态内容组成且没有交互性,组件的 golden 测试以更低的成本提供同等级别的检查。如果屏幕动态变化(流、聊天),screenshot 测试需要复杂的数据配置和等待时间。在这种情况下,对基础状态(空列表、加载中)使用 screenshot,对列表中的单个卡片使用 golden。

Android 的 UI Automator 和 Firebase Test Lab

UI Automator — 用于跨应用程序 UI 测试的 Android 框架。可以通过 UiDevice.takeScreenshot() 捕获截图。与 Espresso(在单个应用程序内部工作)不同,UI Automator 可以与系统对话框(权限、通知)和其他应用程序进行交互。UI Automator 上的 Screenshot 测试:打开应用程序,等待加载,捕获截图,与参考进行比较。

kotlin
class LoginScreenScreenshotTest {

    @get:Rule
    val rule = ComposeTestRule.createAndroidComposeRule<MainActivity>()

    @Test
    fun login_screen_default() {
        val device = UiDevice.getInstance(
            InstrumentationRegistry.getInstrumentation()
        )

        // 等待屏幕加载
        IdlingRegistry.getInstance().waitForIdle()

        // 进行截图
        val screenshot = device.takeScreenshot()
        val golden = loadGolden("login_default.png")

        // 与基准比较
        val diff = ImageComparator.compare(screenshot, golden)
        assertTrue(diff.similarity > 0.98)
    }
}

Firebase Test Lab — Google Cloud 服务,用于在数百台真实设备上并行运行工具测试。Firebase Test Lab 上的 Screenshot 测试在不同设备(Pixel 7、Galaxy S24、Xiaomi 14)上捕获截图并与参考图进行比较。优势:一个测试在 10-15 分钟内检查 20 台设备上的 UI。缺点:成本(每次测试在 20 台设备上 $1-5)。Firebase Test Lab 通过 gcloud CLI 或 Gradle 插件与 CI 集成。

Shot:用于简化 screenshot 测试的库

Shot — Android 上用于 screenshot 测试的库,方便截图的创建和比较。Shot 基于 Espresso 和 UI Automator 工作,添加了 golden 管理(创建、更新、删除)、阈值比较(像素或百分比)和 HTML 报告生成。Shot 适合希望快速实施 screenshot 测试而无需编写自己的图像比较基础设施的项目。

iOS 的 XCUITest 和 Xcode Cloud

XCUITest — Apple 框架,用于 iOS、iPadOS 和 tvOS 应用程序的 UI 测试。XCUITest 上的 screenshot 测试使用 XCUIScreen.main.screenshot() 捕获屏幕,并使用 XCAttachment 保存截图。XCUITest 模拟用户操作:tap、swipe、typeText,并在每个步骤后捕获截图。在 Xcode 16+ 中,添加了通过 XCTAttachment 将截图与参考图进行比较的内置支持。

swift
final class LoginScreenScreenshotTests: XCTestCase {

    var app: XCUIApplication!

    override func setUp() {
        super.setUp()
        app = XCUIApplication()
        app.launch()
    }

    func test_login_initial_state() {
        let loginButton = app.buttons["login_button"]
        XCTAssertTrue(loginButton.exists)

        // 进行截图
        let screenshot = app.screenshot()
        let attachment = XCTAttachment(screenshot: screenshot)
        attachment.name = "Login-Screen-Initial"
        attachment.lifetime = .keepAlways
        add(attachment)

        // 与基准比较(需要 XCTAttachment + golden)
        assertScreenshot(
            screenshot: screenshot,
            goldenName: "login_initial_state"
        )
    }
}

Xcode Cloud — Apple 的云 CI,用于构建和测试 iOS 应用程序。Xcode Cloud 支持在模拟器上运行 XCUITest 测试。Screenshot 测试可以在多个模拟器上并行运行(iPhone 15、iPhone 15 Pro Max、iPad Pro)。结果:带附件的 XCResult Bundle。Xcode Cloud 未内置在 GitHub/GitLab 中 — 请使用 Xcode Cloud Webhooks 进行集成。替代方案:使用 macos-14 和 xcodebuild 的 GitHub Actions。

比较框架 — iOSSnapshotTestCase (Uber) 如果在模拟器上运行,也可用于 screenshot 测试。SwiftSnapshotTesting (pointfree) 更专注于组件的 golden 测试。对于 iOS 上的 screenshot 测试,请使用内置工具 XCUITest + XCTAttachment + 自定义 ImageComparator(Pixelmator 或 AImage)。在 CI 中使用模拟器 — 在真实设备上,screenshot 测试只能通过 Device Farm(AWS Device Farm)工作。

CI 中 screenshot 测试的自动化流程

Baseline 管理 — 参考截图存储在仓库(Git LFS)或 S3 中。每个截图按照模板命名:{testName}_{device}_{orientation}_{locale}.png。示例:loginScreenPixel7PortraitRu.png。添加新设备或 locale 时,会创建新的 baseline。UI 变更时,旧的 baseline 在 code review 后被新的 baseline 替代。Baseline 是代码库的一部分,就像测试源代码一样。

CI Pipeline — (1) 构建应用程序。(2) 在模拟器/仿真器上运行 screenshot 测试。(3) 将截图与 baseline 进行比较。(4) 如果不匹配 — 生成 diff 图像。(5) 上传 diff 特征物(actual、expected、diff — 三个文件)。(6) 发布带有结果表的 HTML 报告。(7) 如果超过阈值 — 测试失败。(8) 审查人员检查 diff 特征物并做出决定:批准(更新 baseline)或拒绝(修复代码)。

阈值和容限 — 绝对的像素级比较过于严格。请使用 SSIM(Structural Similarity Index)或 MSE(Mean Squared Error)。SSIM 0.98 = 98% 结构相似度 — 一个好的阈值。不同屏幕可能需要不同的阈值:深色主题(更多黑色 — 更高精度)、渐变(更多噪声 — 更低精度)。通过参数每个测试单独配置阈值:@ScreenshotTest(threshold = 0.99)。

Device Farm vs 模拟器 — 在真实设备(Firebase Test Lab、AWS Device Farm)上的测试提供最大真实性,但缓慢且需要付费。在模拟器/仿真器上的测试 — 快速免费,但无法展示真实设备特征(不同 GPU、屏幕显色、像素密度)。策略:模拟器用于 pre-merge 检查(5 分钟),Device Farm 用于 nightly(30 分钟,20 台设备)。在 IT Sectr,我们使用 Firebase Test Lab 在顶级 10 款 Android 设备上进行夜间运行。

常见问题

Screenshot Test vs Golden Test — 应该选择哪一个?

Golden Test — 用于在每次提交时快速检查单个 UI 组件(50-200 毫秒)。Screenshot Test — 用于在发版前在真实设备上对完整屏幕进行 E2E 检查(2-30 秒)。两者都用:golden 用于 Design System 组件,screenshot 用于关键用户路径。80/20 的比例对大多数项目来说是最佳的。

应该使用什么阈值来比较截图?

SSIM 0.98 — 对大多数屏幕来说是一个好的起始阈值。对于深色主题可以使用 0.99(更高对比度 — 更精确的比较)。对于带有渐变和图像的屏幕 — 0.95-0.97。不要使用绝对像素级比较(MSE = 0) — 由于反锯餍和 GPU 差异,它会产生 20-30% 的假阳性。针对每个测试单独配置阈值。

应该多久更新一次 baseline 截图?

每次故意的 UI 变更时 — 颜色、字体、边距、图标的变更,添加/删除元素。不要在环境变更时更新 baseline(操作系统版本、CI 中的字体) — 这是 flaky 测试的标志。Baseline 只由开发人员在 code review 后本地更新:删除旧的 baseline,以 record=true 运行测试,检查新的截图,提交代码。

可以不使用 UI Automator 进行 screenshot 测试吗?

可以 — 通过 Android 上的 Espresso 和 iOS 上的 XCUITest。Espresso 在应用程序进程内部工作,不需要 Accessibility Service(像 UI Automator 那样)。XCUITest — Apple 的标准 UI 测试框架。对于 screenshot 测试,差异很小:XCUITest 稍微更稳定(原生 Apple API),UI Automator 稍微更灵活(进程间通信)。

Screenshot 测试会放缓发版周期吗?

如果配置得当 — 不会。Pre-merge:只在变更的屏幕上运行 screenshot 测试(30-60 秒)。Nightly:在 Device Farm 上完整运行(30 分钟,20 台设备)。在模拟器上 screenshot 测试的执行时间:每个屏幕 2-10 秒。20 个屏幕 = 40-200 秒。这比手动测试一个屏幕的时间(5-10 分钟)还要少。

总结

  • Screenshot Test — 通过在真实设备上捕获和比较截图来 E2E 检查 UI
  • 与 Golden Test 的区别 — screenshot 测试带导航的完整屏幕,golden 测试单个组件
  • Android — UI Automator、Espresso、Firebase Test Lab、用于 golden 管理的 Shot 库
  • iOS — XCUITest 以 XCUIScreen.screenshot()、Xcode Cloud、Uber 的 iOSSnapshotTestCase
  • CI Pipeline — 在模拟器上 pre-merge(快速),在 Device Farm 上 nightly(真实)
  • Baseline — 存储在 Git LFS 中,按照模板命名 {test}_{device}_{orientation}_{locale}
  • 阈值 — 以 SSIM 0.98 作为起始阈值,可针对每个测试单独配置

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读