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-тестът генерира diff с подчертаване на променените пиксели
  • 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) Ако изображенията съвпадат — тестът е зелен. Ако се различават — тестът е червен с diff. Решение: или промените са очаквани (актуализираме golden), или е грешка.

Как се генерира 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 KB в зависимост от сложността. За проект с 500 golden-теста това е ~100-400 MB в хранилището. Решения: (1) съхраняване на golden в Git LFS. (2) Използване на PNG компресия (pngcrush, oxipng). (3) Съхраняване на golden в отделно хранилище (S3) и изтегляне при изграждане. В IT Sectr съхраняваме golden в Git LFS с праг от 1 MB на файл — това е достатъчно за 90% от тестовете.

Flaky golden тестове и тяхното решение

Flaky golden тестове — основният проблем на golden-тестовете. Различни GPU, версии на шрифтове и антиалиасинг дават микро-разлики в пикселите. Решения: threshold (допустим процент различни пиксели), fuzzy comparison (размито сравнение) и изпълнение на идентични CI агенти (същият GPU, OS, версия на емулатор). В 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 (извънекранен буфер)Устройство/Емулатор
Скорост50-200 ms на тест2-30 секунди на тест
АнимацииНе се поддържатПоддържат се (с паузи)
CI без GPUРаботи (Layoutlib)Изисква емулатор
Сложност на настройкатаНискаВисока (Емулатор/Device Farm)
FlakinessСредна (различни GPU)Висока (емулатор, време)

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

Golden vs Screenshot — golden-тестове за проверка на отделни UI компоненти (бутон, карта, диалог) при всеки commit. 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 анимации на промените (преди/след/diff), което е удобно за преглед на код. Формат на golden-файловете: PNG + JSON метаданни.

Актуализиране на golden — след преднамерена промяна на UI, разработчикът изтрива старите golden-файлове и пуска тестовете с флаг record. Paparazzi създава отново всички golden-файлове. След това разработчикът commit-ва новия golden заедно с промяната на кода. При преглед на код, рецензентът вижда 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 за всеки поддържан форм фактор на устройство поотделно. Не използвайте един golden за различни размери — това ще доведе до flaky тестове.

Работа с golden-файлове в CI и управление на актуализации

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

Размер на хранилището — golden-файловете растат бързо. 500 теста = 100-400 MB 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/.

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

Кога да актуализирате golden — само след съзнателна промяна на UI. Промяна на шрифт, цвят, разстояние, икона — golden трябва да се актуализира. Добавяне на нов бутон, пренареждане на елементи — golden трябва да се актуализира. Поправка на грешка, която променя външния вид — golden трябва да се актуализира. Рефакториране без промяна на UI — golden не трябва да се актуализира. Ако golden се променя без промяна на UI кода — това е flaky test, причинен от средата, търсете причината в CI агентите или версиите на зависимостите.

Често задавани въпроси

С какво Golden Test се различава от Screenshot Test?

Golden Test — snapshot-тест на ниво компонент в unit-test среда (бърз, без емулатор). Screenshot Test — заснемане на целия екран на устройство или емулатор (бавен, но реалистичен). Golden работи с извънекранен буфер, screenshot — с реален дисплей. Golden е подходящ за CI при всеки commit, screenshot — за nightly преди пускане.

Как да се справим с flaky golden тестове?

Основни причини: (1) Различни GPU на CI — използвайте идентични CI агенти. (2) Различни версии на шрифтове — фиксирайте версията на ОС. (3) Различен антиалиасинг — настройте 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 за коректност, commit-ва промените заедно с кода. Автоматичното приемане на CI ще доведе до пропускане на грешки в UI.

Забавя ли Golden Test изграждането?

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

Обобщение

  • Golden Test — визуално тестване на UI компоненти чрез сравнение с еталонно PNG изображение
  • Процес — рендер на компонент в извънекранен буфер, сравнение пиксел по пиксел, 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 MB за 500 теста)
  • Flakiness — свързан с GPU, шрифтове и антиалиасинг; решава се с threshold и идентични CI агенти

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

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също