Golden Test (snapshot-test, testowanie wzorcowe) — metoda wizualnego testowania UI, w której aktualny render komponentu porównywany jest z wcześniej zapisanym obrazem wzorcowym (plik golden). Jeśli zmiany pikseli przekraczają zadany próg, test kończy się niepowodzeniem i generuje obraz diff. Deweloper przegląda diff i albo akceptuje zmiany (aktualizuje golden), albo naprawia błąd. Więcej w artykule Meta Engineering o Paparazzi.
Najważniejsze
Golden Test — to zautomatyzowane sprawdzanie wyglądu komponentu poprzez porównanie piksel po pikselu z wzorcem. Proces: (1) deweloper lub tester tworzy pierwszy zrzut komponentu — to jest „złoty“ (wzorzec). (2) Plik golden jest zapisywany w repozytorium obok testu. (3) Przy kolejnych uruchomieniach test renderuje komponent ponownie i porównuje z zapisanym golden. (4) Jeśli obrazy są zgodne — test jest zielony. Jeśli się różnią — test jest czerwony z diffem. Decyzja: albo zmiany są oczekiwane (aktualizujemy golden), albo to błąd.
Jak generowany jest golden — biblioteka renderuje komponent w buforze pozuekranowym (Android: Canvas, iOS: UIGraphicsImageRenderer) bez rzeczywistego wyświetlacza. Oznacza to, że golden-testy działają na CI bez emulatora ekranu (virtual display), co przyspiesza wykonanie. Paparazzi na Android używa Layoutlib z Android Studio — tego samego silnika, co Layout Editor. iOSSnapshotTestCase używa renderowania UIKit do CGImage. Rezultat — plik PNG o stałym rozmiarze.
Pliki golden — zrzut PNG jednego ekranu (1080x1920) zajmuje 200-800 KB w zależności od złożoności. Dla projektu z 500 golden-testami to ~100-400 MB w repozytorium. Rozwiązania: (1) przechowywać golden w Git LFS. (2) Używać kompresji PNG (pngcrush, oxipng). (3) Przechowywać golden w osobnym storage (S3) i pobierać przy budowie. W IT Sectr przechowujemy golden w Git LFS z progiem 1 MB na plik — to wystarcza dla 90% testów.
Flaky golden tests — główny problem golden-testów. Różne GPU, wersje czcionek i antyaliasing dają mikro-różnice w pikselach. Rozwiązania: threshold (dopuszczalny procent różniących się pikseli), fuzzy comparison (rozmyte porównanie) i uruchamianie na identycznych agentach CI (taki sam GPU, OS, wersja emulatora). W Paparazzi używane jest porównanie pixel-perfect, dlatego agenci CI muszą być identyczni.
Golden Test — to rodzaj screenshot-testowania ze stałym wzorcem. Termin „złoty“ oznacza, że wzorzec został zatwierdzony (zaakceptowany) przez zespół i przechowywany w repozytorium. Każda zmiana obrazu wymaga świadomej decyzji dewelopera: zaktualizować golden lub poprawić kod. Golden Test działa na poziomie pojedynczych komponentów (Composable, UIView) i nie wymaga rzeczywistego urządzenia.
Screenshot Test — szersze pojęcie. Screenshot-test może przechwytywać cały ekran z rzeczywistymi danymi, nawigacją, paskiem stanu systemu i animacjami. Screenshot-testy często uruchamiane są na rzeczywistych urządzeniach lub emulatorach przez UI Automator (Android) lub XCUITest (iOS). Golden-testy działają w środowisku unit-test (JVM, XCTest) bez emulatora i przechwytują tylko pojedynczy komponent.
| Cecha | Golden Test | Screenshot Test |
|---|---|---|
| Poziom | Komponent/Composable/View | Cały ekran |
| Środowisko | Unit-test (bufor pozuekranowy) | Urządzenie/Emulator |
| Szybkość | 50-200 ms na test | 2-30 sekund na test |
| Animacje | Nie są obsługiwane | Są obsługiwane (z pauzami) |
| CI bez GPU | Działa (Layoutlib) | Wymaga emulatora |
| Trudność konfiguracji | Niska | Wysoka (Emulator/Device Farm) |
| Flakiness | Średnia (różne GPU) | Wysoka (emulator, czas) |
Golden vs Screenshot — golden-testy do sprawdzania pojedynczych komponentów UI (przycisk, karta, dialog) przy każdym commicie. Screenshot-testy — do weryfikacji E2E całych ekranów przed wydaniem. Golden-testy dają szybką informację zwrotną deweloperowi, screenshot-testy — pewność integralności całej aplikacji. W IT Sectr używamy golden-testów dla Pull Request (3-5 minut), a screenshot-testów — nightly (30-60 minut).
Paparazzi — biblioteka od Cash App (Square), która renderuje Android View i Jetpack Compose komponenty do PNG bez emulatora. Używa Layoutlib (tego samego silnika, co Android Studio Preview). Konfiguracja: podłączyć wtyczkę Gradle, napisać test z @Test i @RunWith(PaparazziRule::class), wywołać paparazzi.snapshot(view). Paparazzi nie obsługuje animacji, wideo i Real Device — tylko statyczny render komponentów.
// build.gradle.kts (module)
plugins {
id("app.cash.paparazzi") version "1.3.1"
}
// Golden test dla komponentu 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 — alternatywa dla Paparazzi z obsługą Compose, View i porównywania obrazów. Różnica: Roborazzi działa przez Robolectric i obsługuje threshold (procent dopuszczalnej różnicy pikseli). Zmniejsza to flakiness przy różnych GPU na CI. Roborazzi potrafi również tworzyć animacje GIF zmian (przed/po/diff), co jest wygodne do code review. Format plików golden: PNG + metadane JSON.
Aktualizacja golden — po celowej zmianie UI deweloper usuwa stare pliki golden i uruchamia testy z flagą record. Paparazzi tworzy od nowa wszystkie pliki golden. Następnie deweloper commituje nowe golden razem ze zmianą kodu. W Code Review recenzent widzi diff starych i nowych golden. Jeśli zmiany są zatwierdzone — PR jest mergowany. Jeśli nie — deweloper poprawia kod i ponownie uruchamia testy. Nigdy nie aktualizuj golden automatycznie na CI — tylko lokalnie.
SwiftSnapshotTesting — biblioteka od pointfree.co, twórców Composable Architecture. Obsługuje UIView, UIViewController, CALayer i SwiftUI View. Zasada: assertSnapshot(matching: view, as: .image). Przy pierwszym uruchomieniu golden tworzony jest automatycznie. Przy kolejnych — porównywany. Jeśli różnica przekracza dopuszczalną — test kończy się niepowodzeniem. SwiftSnapshotTesting działa przez UIGraphicsImageRenderer, który jest kompatybilny z 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 (dawniej FBSnapshotTestCase) — biblioteka od Uber dla UIKit. W przeciwieństwie do SwiftSnapshotTesting, iOSSnapshotTestCase wymaga określenia rozmiaru ekranu i orientacji. Pliki golden — PNG w folderze ReferenceImages. Zaleta: działa z UIKit bez SwiftUI i obsługuje iOS 12+. Wada: nie aktualizuje golden automatycznie — trzeba uruchomić z flagą record. SwiftSnapshotTesting jest bardziej nowoczesny i zalecany dla nowych projektów.
Device-specific golden — pliki golden różnią się dla różnych rozmiarów ekranów i orientacji. Standardowe podejście: nazywać golden jako TestName@3x~iPhone14.png. SwiftSnapshotTesting automatycznie dodaje sufiks urządzenia, jeśli podano parametr .image(on: .iPhoneSe). Na Android Paparazzi używa DeviceConfig do ustawienia rozmiaru. Przechowuj golden dla każdego obsługiwanego device form factor osobno. Nie używaj jednego golden dla różnych rozmiarów — to doprowadzi do flaky testów.
CI pipeline — golden-testy powinny być uruchamiane przy każdym Pull Request. Jeśli test kończy się niepowodzeniem, CI pokazuje obraz diff jako artefakt budowania. Deweloper przegląda diff i podejmuje decyzję. Ważne: pliki golden wygenerowane na CI nigdy nie są commitowane automatycznie. Tylko lokalne generowanie przez dewelopera po celowej zmianie. GitHub Actions i GitLab CI obsługują ładowanie artefaktów (png, html) do przeglądania diff w przeglądarce.
Rozmiar repozytorium — pliki golden szybko rosną. 500 testów = 100-400 MB PNG. Rozwiązania: (1) Git LFS — każdy golden przechowywany w LFS, klonowany tylko przy checkout. (2) Przechowywać golden w osobnym repozytorium i podłączać jako submoduł. (3) S3 + buforowanie — golden na S3, CI pobiera tylko zmienione pliki po sumie kontrolnej. W IT Sectr używamy Git LFS z track *.png filter=lfs diff=lfs merge=lfs text=false. Lokalnie golden leżą w src/test/goldens/.
Code Review golden — zwykły git diff nie pokazuje zmian PNG. Rozwiązania: (1) GitHub otwiera obrazy PNG po kliknięciu. (2) Używać Review Apps, gdzie golden-diff jest widoczny w przeglądarce. (3) Generować raport HTML z kolumnami przed/po/diff. Paparazzi tworzy raport HTML z trzema kolumnami: actual, expected, diff. Raport jest dołączany do artefaktów CI. Recenzenci przeglądają raport bez pobierania plików lokalnie.
Kiedy aktualizować golden — tylko po świadomej zmianie UI. Zmiana czcionki, koloru, odstępu, ikony — golden powinien być zaktualizowany. Dodanie nowego przycisku, przestawienie elementów — golden powinien być zaktualizowany. Poprawka błędu zmieniająca wygląd — golden powinien być zaktualizowany. Refaktoryzacja bez zmiany UI — golden nie powinien być aktualizowany. Jeśli golden zmienia się bez zmiany kodu UI — to flaky test spowodowany środowiskiem, szukaj przyczyny w agentach CI lub wersjach zależności.
Często zadawane pytania
Golden Test — snapshot-test na poziomie komponentu w środowisku unit-test (szybki, bez emulatora). Screenshot Test — przechwytywanie całego ekranu na urządzeniu lub emulatorze (wolny, ale realistyczny). Golden działa z buforem pozuekranowym, screenshot — z rzeczywistym wyświetlaczem. Golden nadaje się do CI przy każdym commicie, screenshot — do nightly przed wydaniem.
Główne przyczyny: (1) Różne GPU na CI — używaj identycznych agentów CI. (2) Różne wersje czcionek — ustal wersję OS. (3) Różny anti-aliasing — skonfiguruj threshold (Roborazzi, iOSSnapshotTestCase). (4) Animacje — wyłączaj animacje w testach. (5) Elementy systemowe (pasek stanu) — używaj bezramkowego device config. Paparazzi nie jest podatny na flakiness dzięki Layoutlib.
Tak. Paparazzi ma wbudowaną obsługę Compose przez paparazzi.snapshot { }. Roborazzi również obsługuje Compose. W iOS SwiftSnapshotTesting działa z SwiftUI przez UIHostingController. Komponenty Compose są renderowane przez Layoutlib, SwiftUI — przez UIKit. Ograniczenie: nie są obsługiwane animacje Compose i SwiftUI — golden-test przechwytuje tylko stan początkowy.
Nigdy nie automatyzuj akceptowania golden na CI. Tylko lokalnie: deweloper usuwa stare pliki golden z katalogu i uruchamia testy z flagą record (Paparazzi: record=true, SwiftSnapshotTesting: record=true). Pliki golden są odtwarzane. Deweloper przegląda każdy golden pod kątem poprawności, commituje zmiany wraz z kodem. Automatyczne akceptowanie na CI doprowadzi do przeoczenia błędów UI.
Golden-testy są szybsze niż testy instrumentalne (UI Automator, XCUITest). Jeden golden-test wykonuje się w 50-200 ms (Paparazzi: 100-150 ms na średnim MacBook Pro). 500 golden-testów = 25-100 sekund. Porównaj z screenshot-testami przez emulator: 5-30 sekund na test. Golden-testy nie spowalniają budowania: 100 testów = ~15 sekund, co jest akceptowalne dla weryfikacji pre-merge.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również