Golden Test (snapshot-test, testare etalon) — metodă de testare vizuală a UI în care randarea curentă a componentei este comparată cu o imagine etalon salvată anterior (fișier golden). Dacă modificările pixelilor depășesc un prag stabilit, testul eșuează și generează o imagine diff. Dezvoltatorul verifică diff-ul și fie acceptă modificările (actualizează golden), fie remediază bug-ul. Mai multe în articolul Meta Engineering despre Paparazzi.
Principalele puncte
Golden Test — este o verificare automatizată a aspectului componentei prin compararea pixel cu pixel cu etalonul. Proces: (1) dezvoltatorul sau testerul realizează prima captură a componentei — acesta este „golden“ (etalonul). (2) Fișierul golden este salvat în depozit lângă test. (3) La rulările ulterioare, testul randază din nou componenta și o compară cu golden-ul salvat. (4) Dacă imaginile coincid — testul este verde. Dacă diferă — testul este roșu cu diff. Decizia: fie modificările sunt așteptate (actualizăm golden), fie este o eroare.
Cum se generează golden — biblioteca randază componenta într-un buffer în afara ecranului (Android: Canvas, iOS: UIGraphicsImageRenderer) fără afișaj real. Aceasta înseamnă că golden-testurile funcționează pe CI fără emulator de ecran (virtual display), ceea ce accelerează execuția. Paparazzi pe Android folosește Layoutlib din Android Studio — același motor ca Layout Editor. iOSSnapshotTestCase folosește randarea UIKit în CGImage. Rezultatul — un fișier PNG de dimensiune fixă.
Fișierele golden — captura PNG a unui ecran (1080x1920) ocupă 200-800 KB în funcție de complexitate. Pentru un proiect cu 500 golden-testuri, aceasta înseamnă ~100-400 MB în depozit. Soluții: (1) stocarea golden în Git LFS. (2) Utilizarea compresiei PNG (pngcrush, oxipng). (3) Stocarea golden într-un stoc separat (S3) și descărcarea la construire. În IT Sectr stocăm golden în Git LFS cu un prag de 1 MB per fișier — acest lucru este suficient pentru 90% din teste.
Testele flaky golden — principala problemă a golden-testurilor. GPU-uri diferite, versiuni de fonturi și anti-aliasing generează micro-diferențe în pixeli. Soluții: threshold (procentul admisibil de pixeli diferiți), fuzzy comparison (comparare neclară) și rularea pe aceiași agenți CI (același GPU, OS, versiune de emulator). În Paparazzi se utilizează compararea pixel-perfect, prin urmare agenții CI trebuie să fie identici.
Golden Test — este un tip de screenshot-testare cu un etalon fix. Termenul „golden“ înseamnă că etalonul a fost aprobat (acceptat) de echipă și stocat în depozit. Orice modificare a imaginii necesită o decizie conștientă a dezvoltatorului: actualizarea golden sau corectarea codului. Golden Test funcționează la nivelul componentelor individuale (Composable, UIView) și nu necesită un dispozitiv real.
Screenshot Test — un concept mai larg. Screenshot-testul poate captura întregul ecran cu date reale, navigație, bara de stare a sistemului și animații. Screenshot-testurile sunt adesea rulate pe dispozitive reale sau emulatoare prin UI Automator (Android) sau XCUITest (iOS). Golden-testurile funcționează în mediul unit-test (JVM, XCTest) fără emulator și capturează doar o singură componentă.
| Caracteristică | Golden Test | Screenshot Test |
|---|---|---|
| Nivel | Componentă/Composable/View | Ecran întreg |
| Mediu | Unit-test (buffer în afara ecranului) | Dispozitiv/Emulator |
| Viteză | 50-200 ms per test | 2-30 secunde per test |
| Animații | Nu sunt suportate | Sunt suportate (cu pauze) |
| CI fără GPU | Funcționează (Layoutlib) | Necesită emulator |
| Complexitatea configurării | Scăzută | Ridicată (Emulator/Device Farm) |
| Flakiness | Medie (GPU diferite) | Ridicată (emulator, timp) |
Golden vs Screenshot — golden-testurile pentru verificarea componentelor UI individuale (buton, card, dialog) la fiecare commit. Screenshot-testurile — pentru verificarea E2E a ecranelor întregi înainte de lansare. Golden-testurile oferă feedback rapid dezvoltatorului, screenshot-testurile — încredere în integritatea întregii aplicații. În IT Sectr folosim golden-testuri pentru Pull Request (3-5 minute), iar screenshot-testuri — nightly (30-60 minute).
Paparazzi — bibliotecă de la Cash App (Square) care randază componente Android View și Jetpack Compose în PNG fără emulator. Folosește Layoutlib (același motor ca Android Studio Preview). Configurare: conectarea pluginului Gradle, scrierea testului cu @Test și @RunWith(PaparazziRule::class), apelarea paparazzi.snapshot(view). Paparazzi nu suportă animații, video și Real Device — doar randare statică a componentelor.
// build.gradle.kts (module)
plugins {
id("app.cash.paparazzi") version "1.3.1"
}
// Golden test pentru componenta 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 — alternativă la Paparazzi cu suport pentru Compose, View și compararea imaginilor. Diferența: Roborazzi funcționează prin Robolectric și suportă threshold (procentul de diferență admisibilă a pixelilor). Aceasta reduce flakiness-ul la GPU diferite pe CI. Roborazzi poate crea și animații GIF ale modificărilor (înainte/după/diff), ceea ce este convenabil pentru revizuirea codului. Formatul fișierelor golden: PNG + metadate JSON.
Actualizarea golden — după o modificare intenționată a UI, dezvoltatorul șterge fișierele golden vechi și rulează testurile cu flagul record. Paparazzi creează din nou toate fișierele golden. Apoi dezvoltatorul commit-uiește noul golden împreună cu modificarea codului. În revizuirea codului, recenzentul vede diff-ul golden-urilor vechi și noi. Dacă modificările sunt aprobate — PR-ul este îmbinat. Dacă nu — dezvoltatorul corectează codul și rulează din nou testurile. Nu actualizați niciodată golden automat pe CI — doar local.
SwiftSnapshotTesting — bibliotecă de la pointfree.co, creatorii Composable Architecture. Suportă UIView, UIViewController, CALayer și SwiftUI View. Principiu: assertSnapshot(matching: view, as: .image). La prima rulare, golden este creat automat. La următoarele — este comparat. Dacă diferența depășește limita admisibilă — testul eșuează. SwiftSnapshotTesting funcționează prin UIGraphicsImageRenderer, care este compatibil cu 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 (fost FBSnapshotTestCase) — bibliotecă de la Uber pentru UIKit. Spre deosebire de SwiftSnapshotTesting, iOSSnapshotTestCase necesită specificarea dimensiunii ecranului și orientării. Fișierele golden — PNG în folderul ReferenceImages. Avantaj: funcționează cu UIKit fără SwiftUI și suportă iOS 12+. Dezavantaj: nu actualizează golden automat — trebuie rulat cu flagul record. SwiftSnapshotTesting este mai modern și recomandat pentru proiecte noi.
Golden specific dispozitivului — fișierele golden diferă pentru diferite dimensiuni de ecran și orientări. Abordarea standard: denumirea golden ca TestName@3x~iPhone14.png. SwiftSnapshotTesting adaugă automat sufixul dispozitivului dacă este dat parametrul .image(on: .iPhoneSe). Pe Android, Paparazzi folosește DeviceConfig pentru setarea dimensiunii. Stocați golden pentru fiecare form factor de dispozitiv suportat separat. Nu folosiți un singur golden pentru dimensiuni diferite — aceasta va duce la teste flaky.
Pipeline CI — golden-testurile ar trebui să ruleze la fiecare Pull Request. Dacă testul eșuează, CI arată imaginea diff ca artefact de construire. Dezvoltatorul verifică diff-ul și ia o decizie. Important: fișierele golden generate pe CI nu sunt niciodată comițate automat. Doar generare locală de către dezvoltator după o modificare intenționată. GitHub Actions și GitLab CI suportă încărcarea artefactelor (png, html) pentru vizualizarea diff-ului în browser.
Dimensiunea depozitului — fișierele golden cresc rapid. 500 de teste = 100-400 MB PNG. Soluții: (1) Git LFS — fiecare golden este stocat în LFS, clonat doar la checkout. (2) Stocarea golden într-un depozit separat și conectarea ca submodul. (3) S3 + memorare în cache — golden pe S3, CI descarcă doar fișierele modificate după checksum. În IT Sectr folosim Git LFS cu track *.png filter=lfs diff=lfs merge=lfs text=false. Local, golden se află în src/test/goldens/.
Revizuirea codului golden — git diff obișnuit nu arată modificările PNG. Soluții: (1) GitHub deschide imaginile PNG la clic. (2) Utilizarea Review Apps, unde golden-diff este vizibil în browser. (3) Generarea unui raport HTML cu coloanele înainte/după/diff. Paparazzi creează un raport HTML cu trei coloane: actual, expected, diff. Raportul este atașat la artefactele CI. Recenzorii verifică raportul fără a descărca fișierele local.
Când să actualizați golden — doar după o modificare conștientă a UI. Modificarea fontului, culorii, spațierii, pictogramei — golden trebuie actualizat. Adăugarea unui buton nou, rearanjarea elementelor — golden trebuie actualizat. Corectarea unei erori care schimbă aspectul — golden trebuie actualizat. Refactorizarea fără modificarea UI — golden nu trebuie actualizat. Dacă golden se modifică fără modificarea codului UI — este un test flaky cauzat de mediu, căutați cauza în agenții CI sau versiunile dependențelor.
Întrebări frecvente
Golden Test — snapshot-test la nivel de componentă în mediul unit-test (rapid, fără emulator). Screenshot Test — capturarea întregului ecran pe dispozitiv sau emulator (lent, dar realist). Golden funcționează cu buffer în afara ecranului, screenshot — cu afișajul real. Golden este potrivit pentru CI la fiecare commit, screenshot — pentru rulări nightly înainte de lansare.
Cauze principale: (1) GPU diferite pe CI — utilizați agenți CI identici. (2) Versiuni diferite de fonturi — fixați versiunea OS. (3) Anti-aliasing diferit — configurați threshold (Roborazzi, iOSSnapshotTestCase). (4) Animații — dezactivați animațiile în teste. (5) Elemente de sistem (bara de stare) — utilizați config fără ramă. Paparazzi nu este susceptibil la flakiness datorită Layoutlib.
Da. Paparazzi are suport încorporat pentru Compose prin paparazzi.snapshot { }. Roborazzi suportă de asemenea Compose. În iOS, SwiftSnapshotTesting funcționează cu SwiftUI prin UIHostingController. Componentele Compose sunt randate prin Layoutlib, SwiftUI — prin randarea UIKit. Limitare: animațiile Compose și SwiftUI nu sunt suportate — golden-testul capturează doar starea inițială.
Nu automatizați niciodată acceptarea golden pe CI. Doar local: dezvoltatorul șterge fișierele golden vechi din director și rulează testurile cu flagul record (Paparazzi: record=true, SwiftSnapshotTesting: record=true). Fișierele golden sunt recreate. Dezvoltatorul verifică fiecare golden pentru corectitudine, commit-uiește modificările împreună cu codul. Acceptarea automată pe CI va duce la trecerea cu vederea a erorilor UI.
Golden-testurile sunt mai rapide decât testele instrumentale (UI Automator, XCUITest). Un golden-test se execută în 50-200 ms (Paparazzi: 100-150 ms pe un MacBook Pro mediu). 500 golden-testuri = 25-100 secunde. Comparați cu screenshot-testurile prin emulator: 5-30 secunde per test. Golden-testurile nu încetinesc construirea: 100 de teste = ~15 secunde, ceea ce este acceptabil pentru verificarea pre-merge.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și