Golden Test — что это, как работает snapshot-тестирование и применение

Автор: IT Sectr Опубликовано: 2026-04-10 Время чтения: 9 мин

Golden Test (snapshot-тест, эталонное тестирование) — метод визуального тестирования UI, при котором текущий рендер компонента сравнивается с заранее сохранённым эталонным изображением (golden-файлом). Если пиксельные изменения превышают заданный порог, тест падает и генерирует diff-изображение. Разработчик просматривает diff и либо принимает изменения (обновляет golden), либо фиксит баг. Подробнее — в статье Meta Engineering о Paparazzi.

Главное

  • Golden Test — сравнение текущего UI с эталонным изображением для выявления визуальных регрессий
  • Diff-изображение — при несовпадении golden-тест генерирует дифф с подсветкой изменённых пикселей
  • Android — Paparazzi и Roborazzi для screenshot-тестирования compose и view-компонентов
  • iOS — SwiftSnapshotTesting (pointfree.co) и iOSSnapshotTestCase от Uber для SwiftUI и UIKit
  • CI-интеграция — golden-тесты запускаются на CI и падают при неожиданных изменениях UI

Что такое Golden Test и как он работает?

Golden Test — это автоматизированная проверка внешнего вида компонента путём попиксельного сравнения с эталоном. Процесс: (1) разработчик или тест создаёт первый снимок компонента — это «golden» (эталон). (2) Файл golden сохраняется в репозиторий рядом с тестом. (3) При последующих запусках тест рендерит компонент заново и сравнивает с сохранённым golden. (4) Если изображения совпадают — тест зелёный. Если различаются — тест красный с диффом. Решение: либо изменения ожидаемые (обновляем golden), либо это баг.

Как генерируется golden — библиотека рендерит компонент в off-screen buffer (Android: Canvas, iOS: UIGraphicsImageRenderer) без реального дисплея. Это означает, что golden-тесты работают на CI без эмулятора экрана (virtual display), что ускоряет выполнение. Paparazzi на Android использует Layoutlib из Android Studio — тот же движок, что и Layout Editor. iOSSnapshotTestCase использует UIKit-рендеринг в CGImage. Результат — PNG-файл фиксированного размера.

Размер golden-файлов и управление хранилищем

Golden-файлы — PNG-снимок одного экрана (1080x1920) занимает 200-800 КБ в зависимости от сложности. Для проекта с 500 golden-тестами это ~100-400 МБ в репозитории. Решения: (1) хранить golden в Git LFS. (2) Использовать сжатие PNG (pngcrush, oxipng). (3) Хранить golden на отдельном storage (S3) и подтягивать при сборке. В IT Sectr мы храним golden в Git LFS с порогом в 1 МБ на файл — этого достаточно для 90% тестов.

Flaky golden tests и их решение

Flaky golden tests — главная проблема golden-тестов. Разные GPU, версии шрифтов и антиалиасинг дают микро-различия в пикселях. Решения: threshold (допустимый процент различающихся пикселей), fuzzy comparison (размытое сравнение), и запуск на одинаковых CI-агентах (одинаковый GPU, ОС, версия эмулятора). В Paparazzi используется pixel-perfect сравнение, поэтому CI-агенты должны быть идентичными.

Golden Test vs Screenshot Test: в чём разница?

Golden Test — это вид screenshot-тестирования с фиксированным эталоном. Термин «golden» означает, что эталон утверждён (принят) командой и хранится в репозитории. Любое изменение изображения требует осознанного решения разработчика: обновить golden или исправить код. Golden Test работает на уровне отдельных компонентов (Composable, UIView) и не требует реального устройства.

Screenshot Test — более широкое понятие. Screenshot-тест может захватывать целый экран с реальными данными, навигацией, системным статус-баром и анимациями. Screenshot-тесты часто запускаются на реальных устройствах или эмуляторах через UI Automator (Android) или XCUITest (iOS). Golden-тесты работают в unit-test окружении (JVM, XCTest) без эмулятора и захватывают только отдельный компонент.

ХарактеристикаGolden TestScreenshot Test
УровеньКомпонент/Composable/ViewЦелый экран
ОкружениеUnit-test (off-screen buffer)Device/Emulator
Скорость50-200 мс на тест2-30 секунд на тест
АнимацииНе поддерживаютсяПоддерживаются (с паузами)
CI без GPUРаботает (Layoutlib)Требует эмулятора
Сложность настройкиНизкаяВысокая (Emulator/Device Farm)
FlakinessСредняя (разные GPU)Высокая (эмулятор, время)

Стратегия покрытия: golden vs screenshot

Golden vs Screenshot — golden-тесты для проверки отдельных UI-компонентов (кнопка, карточка, диалог) при каждом коммите. Screenshot-тесты — для E2E-проверки целых экранов перед релизом. Golden-тесты дают быструю обратную связь разработчику, screenshot-тесты — уверенность в целостности всего приложения. В IT Sectr мы используем golden-тесты для Pull Request (3-5 минут), а screenshot-тесты — nightly (30-60 минут).

Paparazzi и Roborazzi: snapshot-тестирование на Android

Paparazzi — библиотека от Cash App (Square), которая рендерит Android View и Jetpack Compose компоненты в PNG без эмулятора. Использует Layoutlib (тот же движок, что и Android Studio Preview). Настройка: подключить Gradle-плагин, написать тест с @Test и @RunWith(PaparazziRule::class), вызвать paparazzi.snapshot(view). Paparazzi не поддерживает анимации, видео и Real Device — только статический рендер компонентов.

kotlin
// build.gradle.kts (module)
plugins {
    id("app.cash.paparazzi") version "1.3.1"
}

// Golden test для Compose компонента
class ButtonGoldenTest {

    @get:Rule
    val paparazzi = Paparazzi(
        Paparazzi.PaparazziSnapshotConfig(
            deviceConfig = DeviceConfig.PIXEL_6,
            theme = "android:Theme.Material.Light.NoActionBar"
        )
    )

    @Test
    fun primary_button() {
        paparazzi.snapshot {
            Button(
                onClick = { },
                modifier = Modifier.width(200.dp)
            ) {
                Text("Submit")
            }
        }
    }
}

Roborazzi — альтернатива Paparazzi с поддержкой Compose, View и сравнения изображений. Отличие: Roborazzi работает через Robolectric и поддерживает threshold (процент допустимого расхождения пикселей). Это снижает flakiness при разных GPU на CI. Roborazzi также умеет создавать GIF-анимацию изменений (до/после/дифф), что удобно для код-ревью. Формат golden-файлов: PNG + JSON-метаданные.

Обновление golden — после intentional изменения UI разработчик удаляет старые golden-файлы и запускает тесты с флагом record. Paparazzi заново создаёт все golden-файлы. Затем разработчик коммитит новые golden вместе с изменением кода. В Code Review reviewer видит diff старых и новых golden. Если изменения одобрены — PR мержится. Если нет — разработчик правит код и перезапускает тесты. Никогда не обновляйте golden автоматически на CI — только локально.

SwiftSnapshotTesting и iOSSnapshotTestCase на iOS

SwiftSnapshotTesting — библиотека от pointfree.co, создатели Composable Architecture. Поддерживает UIView, UIViewController, CALayer и SwiftUI View. Принцип: assertSnapshot(matching: view, as: .image). При первом запуске golden создаётся автоматически. При последующих — сравнивается. Если различие превышает допустимое — тест падает. SwiftSnapshotTesting работает через UIGraphicsImageRenderer, который совместим с CI (Xcode Cloud, GitHub Actions).

swift
import SnapshotTesting
import XCTest

final class ProfileCardSnapshotTests: XCTestCase {

    func test_profile_card_default() {
        let card = ProfileCard(
            name: "Alice",
            avatar: UIImage.testImage(),
            badge: "Pro"
        )
        let controller = UIHostingController(rootView: card)

        assertSnapshot(
            matching: controller,
            as: .image(on: .iPhoneSe),
            record: ProcessInfo.processInfo
                .environment["RECORD"] != nil
        )
    }
}

iOSSnapshotTestCase (бывший FBSnapshotTestCase) — библиотека от Uber для UIKit. В отличие от SwiftSnapshotTesting, iOSSnapshotTestCase требует указания размера экрана и ориентации. Golden-файлы — PNG в папке ReferenceImages. Преимущество: работает с UIKit без SwiftUI и поддерживает iOS 12+. Недостаток: не обновляет golden автоматически — нужно запускать с флагом record. SwiftSnapshotTesting более современен и рекомендуется для новых проектов.

Device-specific golden — golden-файлы различаются для разных размеров экранов и ориентаций. Стандартный подход: именовать golden как TestName@3x~iPhone14.png. SwiftSnapshotTesting автоматически добавляет суффикс устройства, если указан параметр .image(on: .iPhoneSe). На Android Paparazzi использует DeviceConfig для задания размера. Храните golden для каждого поддерживаемого device form factor отдельно. Не используйте один golden для разных размеров — это приведёт к flaky тестам.

Работа с golden-файлами в CI и управление обновлениями

CI pipeline — golden-тесты должны запускаться на каждом Pull Request. Если тест падает, CI показывает diff-изображение как артефакт сборки. Разработчик просматривает diff и принимает решение. Важно: golden-файлы, сгенерированные на CI, никогда не коммитятся автоматически. Только локальная генерация разработчиком после intentional изменения. GitHub Actions и GitLab CI поддерживают загрузку артефактов (png, html) для просмотра diff в браузере.

Размер репозитория — golden-файлы быстро растут. 500 тестов = 100-400 МБ PNG. Решения: (1) Git LFS — каждый golden хранится в LFS, клонируется только при checkout. (2) Хранить golden в отдельном репозитории и подключать как субмодуль. (3) S3 + кэширование — golden на S3, CI скачивает только изменённые файлы по чексумме. В IT Sectr используем Git LFS с track *.png filter=lfs diff=lfs merge=lfs text=false. Локально golden лежат в src/test/goldens/.

Code Review golden — обычный git diff не показывает изменения PNG. Решения: (1) GitHub окрывает PNG-изображения при клике. (2) Использовать Review Apps, где golden-дифф виден в браузере. (3) Генерировать HTML-отчёт с рядом до/после/дифф. Paparazzi создаёт HTML-отчёт с тремя колонками: actual, expected, diff. Отчёт прикрепляется к CI-артефактам. Reviewers просматривают отчёт, не скачивая файлы локально.

Когда обновлять golden — только после осознанного изменения UI. Изменение шрифта, цвета, отступа, иконки — golden должен обновиться. Добавление новой кнопки, перестановка элементов — golden должен обновиться. Баг-фикс, который меняет внешний вид — golden должен обновиться. Рефакторинг без изменения UI — golden не должен обновиться. Если golden меняется без изменения UI-кода — это flaky test из-за окружения, ищите причину в CI-агентах или версиях зависимостей.

Часто задаваемые вопросы

Чем Golden Test отличается от Screenshot Test?

Golden Test — snapshot-тест на уровне компонента в unit-test окружении (быстрый, без эмулятора). Screenshot Test — захват полного экрана на устройстве или эмуляторе (медленный, но реалистичный). Golden работает с off-screen buffer, screenshot — с реальным дисплеем. Golden подходит для CI при каждом коммите, screenshot — для nightly-прогонов перед релизом.

Как бороться с flaky golden-тестами?

Основные причины: (1) Разные GPU на CI — используйте одинаковые CI-агенты. (2) Разные версии шрифтов — фиксируйте версию ОС. (3) Разный anti-aliasing — настройте threshold (Roborazzi, iOSSnapshotTestCase). (4) Анимации — отключайте анимации в тестах. (5) Системные элементы (статус-бар) — используйте безрамочный device config. Paparazzi не подвержен flakiness из-за Layoutlib.

Можно ли использовать Golden Test с Jetpack Compose?

Да. Paparazzi имеет встроенную поддержку Compose через paparazzi.snapshot { }. Roborazzi также поддерживает Compose. В iOS SwiftSnapshotTesting работает с SwiftUI через UIHostingController. Compose-компоненты рендерятся через Layoutlib, SwiftUI — через UIKit-рендеринг. Ограничение: не поддерживаются анимации Compose и SwiftUI — golden-тест захватывает только начальное состояние.

Как автоматически принять изменения golden?

Никогда не автоматизируйте принятие golden на CI. Только локально: разработчик удаляет старые golden-файлы из директории и запускает тесты с флагом record (Paparazzi: record=true, SwiftSnapshotTesting: record=true). Golden-файлы пересоздаются. Разработчик просматривает каждый golden на предмет корректности, коммитит изменения вместе с кодом. Автоматическое принятие на CI приведёт к пропуску багов в UI.

Golden Test замедляет сборку?

Golden-тесты быстрее инструментальных (UI Automator, XCUITest). Один golden-тест выполняется за 50-200 мс (Paparazzi: 100-150 мс на среднем MacBook Pro). 500 golden-тестов = 25-100 секунд. Сравните с screenshot-тестами через эмулятор: 5-30 секунд на тест. Golden-тесты не замедляют сборку: 100 тестов = ~15 секунд, что приемлемо для pre-merge проверки.

Итоги

  • Golden Test — визуальное тестирование UI-компонентов сравнением с эталонным PNG-изображением
  • Процесс — рендер компонента в off-screen buffer, попиксельное сравнение, diff при несовпадении
  • Android — Paparazzi (Compose/View, Layoutlib) и Roborazzi (Compose/View, threshold, Robolectric)
  • iOS — SwiftSnapshotTesting (pointfree) и iOSSnapshotTestCase от Uber для UIKit и SwiftUI
  • CI Pipeline — golden-тесты на каждом PR, diff-артефакты, только локальное обновление golden
  • Git LFS — обязателен для хранения PNG-файлов (100-400 МБ на 500 тестов)
  • Flakiness — связана с GPU, шрифтами и anti-aliasing; решается threshold и идентичными CI-агентами

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также