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), або це баг.

How the golden як генерується — бібліотека рендерить компонент в офекранний буфер (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 на окремому сховищі (S3) і підтягувати при збірці. В IT Sectr ми зберігаємо golden в Git LFS з порогом в 1 МБ на файл — цього достатньо для 90% тестів.

Flaky golden тести та їх вирішення

Flaky golden тести — головна проблема 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 ревьювер бачить 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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