Golden Test (snapshot-тест, еталонско тестирање) — метод визуелног тестирања UI при којем се тренутни рендер компоненте пореди са унапред сачуваном еталонском сликом (golden-фајлом). Ако пикселске промене премаше задати праг, тест пада и генерише diff-слику. Програмер прегледа diff и или прихвата промене (ажурира golden) или исправља баг. Више у чланку Meta Engineering о Paparazzi.
Главно
Golden Test — то је аутоматизована провера изгледа компоненте поређењем пиксел по пиксел са еталоном. Процес: (1) програмер или тестер прави први снимак компоненте — то је „golden“ (еталон). (2) Golden фајл се чува у репозиторијуму поред теста. (3) При наредним покретањима тест рендерује компоненту поново и пореди са сачуваним golden. (4) Ако се слике поклапају — тест је зелен. Ако се разликују — тест је црвен са дифом. Одлука: или су промене очекиване (ажурирамо golden), или је то баг.
Како се генерише golden — библиотека рендерује компоненту ван екрана (Android: Canvas, iOS: UIGraphicsImageRenderer) без правог дисплеја. То значи да golden-тестови раде на CI без емулатора екрана (virtual display), што убрзава извршење. Paparazzi на Android користи Layoutlib из Android Studio — исти мотор као Layout Editor. iOSSnapshotTestCase користи UIKit рендеровање у CGImage. Резултат — PNG фајл фиксне величине.
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 тестови — главни проблем golden-тестова. Различити GPU, верзије фонтова и антиалиасинг дају микро-разлике у пикселима. Решења: threshold (дозвољени проценат различитих пиксела), fuzzy comparison (замагљено поређење) и покретање на истим CI агентима (исти GPU, OS, верзија емулатора). У Paparazzi се користи pixel-perfect поређење, зато CI агенти морају бити идентични.
Golden Test — то је врста screenshot-тестирања са фиксним еталоном. Термин „golden“ значи да је еталон одобрен (прихваћен) од стране тима и чува се у репозиторијуму. Свака промена слике захтева свесну одлуку програмера: ажурирати golden или исправити код. Golden Test ради на нивоу појединачних компоненти (Composable, UIView) и не захтева прави уређај.
Screenshot Test — шири појам. Screenshot-тест може да сними цео екран са правим подацима, навигацијом, системским статус-баром и анимацијама. Screenshot-тестови се често покрећу на правим уређајима или емулаторима преко UI Automator (Android) или XCUITest (iOS). Golden-тестови раде у unit-test окружењу (JVM, XCTest) без емулатора и снимају само појединачну компоненту.
| Карактеристика | Golden Test | Screenshot Test |
|---|---|---|
| Ниво | Компонента/Composable/View | Цео екран |
| Окружење | Unit-test (ван екрана) | Уређај/Емулатор |
| Брзина | 50-200 ms по тесту | 2-30 секунди по тесту |
| Анимације | Нису подржане | Подржане (са паузама) |
| CI без GPU | Ради (Layoutlib) | Захтева емулатор |
| Сложеност подешавања | Ниска | Висока (Емулатор/Device Farm) |
| Flakiness | Средња (различити GPU) | Висока (емулатор, време) |
Golden vs Screenshot — golden-тестови за проверу појединачних UI компоненти (дугме, картица, дијалог) при сваком комиту. Screenshot-тестови — за E2E проверу целих екрана пре издања. Golden-тестови дају брзу повратну информацију програмеру, screenshot-тестови — сигурност у интегритет целе апликације. У IT Sectr користимо golden-тестове за Pull Request (3-5 минута), а screenshot-тестове — nightly (30-60 минута).
Paparazzi — библиотека од Cash App (Square) која рендерује Android View и Jetpack Compose компоненте у PNG без емулатора. Користи Layoutlib (исти мотор као Android Studio Preview). Подешавање: повезати Gradle додатак, написати тест са @Test и @RunWith(PaparazziRule::class), позвати paparazzi.snapshot(view). Paparazzi не подржава анимације, видео и Real Device — само статички рендер компоненти.
// 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-фајлове и покреће тестове са flag record. Paparazzi поново креира све golden-фајлове. Затим програмер комитује нови golden заједно са променом кода. У прегледу кода, рецензент види diff старих и нових golden. Ако су промене одобрене — PR се спаја. Ако не — програмер исправља код и поново покреће тестове. Никад не ажурирајте golden аутоматски на CI — само локално.
SwiftSnapshotTesting — библиотека од pointfree.co, творци Composable Architecture. Подржава UIView, UIViewController, CALayer и SwiftUI View. Принцип: assertSnapshot(matching: view, as: .image). При првом покретању golden се креира аутоматски. При наредним — пореди се. Ако разлика премаши дозвољену — тест пада. SwiftSnapshotTesting ради преко UIGraphicsImageRenderer, који је компатибилан са CI (Xcode Cloud, GitHub Actions).
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 аутоматски — мора се покренути са flag record. SwiftSnapshotTesting је модернији и препоручује се за нове пројекте.
Device-specific golden — golden-фајлови се разликују за различите величине екрана и оријентације. Стандардни приступ: именовати golden као TestName@3x~iPhone14.png. SwiftSnapshotTesting аутоматски додаје суфикс уређаја ако је дат параметар .image(on: .iPhoneSe). На Android Paparazzi користи DeviceConfig за подешавање величине. Чувајте golden за сваки подржани облик уређаја посебно. Немојте користити један golden за различите величине — то ће довести до flaky тестова.
CI pipeline — golden-тестови треба да се покрећу при сваком Pull Request. Ако тест падне, CI приказује diff-слику као артефакт изградње. Програмер прегледа diff и доноси одлуку. Важно: golden-фајлови генерисани на CI се никад аутоматски не комитују. Само локално генерисање од стране програмера после намерне промене. 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 — snapshot-тест на нивоу компоненте у unit-test окружењу (брз, без емулатора). Screenshot Test — снимање целог екрана на уређају или емулатору (спор, али реалистичан). Golden ради ван екрана, screenshot — са правим дисплејем. Golden је погодан за CI при сваком комиту, screenshot — за nightly пре издања.
Главни узроци: (1) Различити GPU на CI — користите исте CI агенте. (2) Различите верзије фонтова — фиксирајте верзију ОС. (3) Различити антиалиасинг — подесите threshold (Roborazzi, iOSSnapshotTestCase). (4) Анимације — искључите анимације у тестовима. (5) Системски елементи (статус-бар) — користите безоквирни device config. Paparazzi није подложан flakiness због Layoutlib.
Да. Paparazzi има уграђену подршку за Compose преко paparazzi.snapshot { }. Roborazzi такође подржава Compose. На iOS SwiftSnapshotTesting ради са SwiftUI преко UIHostingController. Компоненте Compose се рендерују преко Layoutlib, SwiftUI — преко UIKit рендеровања. Ограничење: анимације Compose и SwiftUI нису подржане — golden-тест снима само почетно стање.
Никад не аутоматизујте прихватање golden на CI. Само локално: програмер брише старе golden-фајлове из директоријума и покреће тестове са flag record (Paparazzi: record=true, SwiftSnapshotTesting: record=true). Golden-фајлови се поново креирају. Програмер прегледа сваки golden на исправност, комитује промене заједно са кодом. Аутоматско прихватање на CI ће довести до пропуштања грешака у UI.
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 проверу.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође