Golden Test (test snapshot, test di riferimento) — un metodo di test visivo dell’UI in cui il rendering corrente del componente viene confrontato con un’immagine di riferimento salvata in precedenza (file golden). Se le modifiche ai pixel superano una soglia impostata, il test fallisce e genera un’immagine diff. Lo sviluppatore esamina il diff e accetta le modifiche (aggiorna il golden) o corregge il bug. Per saperne di più, leggi l’articolo di Meta Engineering su Paparazzi.
Punti chiave
Golden Test è un controllo automatico dell’aspetto visivo di un componente tramite confronto pixel per pixel con un riferimento. Il processo: (1) lo sviluppatore o il tester crea il primo snapshot del componente — questo è il “golden” (riferimento). (2) Il file golden viene salvato nel repository accanto al test. (3) Nelle esecuzioni successive, il test renderizza nuovamente il componente e lo confronta con il golden salvato. (4) Se le immagini corrispondono — il test è verde. Se differiscono — il test è rosso con un diff. Decisione: o le modifiche sono previste (aggiornare golden) o è un bug.
Come viene generato il golden — la libreria renderizza il componente in un buffer fuori schermo (Android: Canvas, iOS: UIGraphicsImageRenderer) senza un display reale. Ciò significa che i golden test funzionano su CI senza emulatore dello schermo (virtual display), accelerando l’esecuzione. Paparazzi su Android utilizza Layoutlib di Android Studio — lo stesso motore dell’Editor di layout. iOSSnapshotTestCase utilizza il rendering UIKit in CGImage. Il risultato è un file PNG di dimensioni fisse.
File golden — uno snapshot PNG di uno schermo (1080x1920) occupa 200–800 KB a seconda della complessità. Per un progetto con 500 golden test, sono ~100–400 MB nel repository. Soluzioni: (1) archiviare i golden in Git LFS. (2) Utilizzare la compressione PNG (pngcrush, oxipng). (3) Archiviare i golden su uno storage separato (S3) e scaricarli durante la compilazione. In IT Sectr archiviamo i golden in Git LFS con una soglia di 1 MB per file — sufficiente per il 90% dei test.
Test golden instabili — il problema principale dei golden test. GPU diverse, versioni di font e anti-aliasing producono micro-differenze nei pixel. Soluzioni: soglia (percentuale ammissibile di pixel differenti), confronto fuzzy ed esecuzione su agenti CI identici (stessa GPU, OS, versione emulatore). Paparazzi utilizza il confronto pixel-perfect, quindi gli agenti CI devono essere identici.
Golden Test è un tipo di test screenshot con un riferimento fisso. Il termine “golden” significa che il riferimento è stato approvato dal team e archiviato nel repository. Qualsiasi modifica all’immagine richiede una decisione consapevole dello sviluppatore: aggiornare il golden o correggere il codice. Golden Test funziona a livello di singoli componenti (Composable, UIView) e non richiede un dispositivo reale.
Screenshot Test è un concetto più ampio. Un test screenshot può catturare un intero schermo con dati reali, navigazione, barra di stato del sistema e animazioni. I test screenshot vengono spesso eseguiti su dispositivi reali o emulatori tramite UI Automator (Android) o XCUITest (iOS). I golden test vengono eseguiti in un ambiente di test unitario (JVM, XCTest) senza emulatore e catturano solo un singolo componente.
| Caratteristica | Golden Test | Screenshot Test |
|---|---|---|
| Livello | Componente/Composable/View | Schermo intero |
| Ambiente | Test unitario (buffer fuori schermo) | Dispositivo/Emulatore |
| Velocità | 50–200 ms per test | 2–30 secondi per test |
| Animazioni | Non supportate | Supportate (con pause) |
| CI senza GPU | Funziona (Layoutlib) | Richiede emulatore |
| Complessità di configurazione | Bassa | Alta (Emulatore/Device Farm) |
| Instabilità (Flakiness) | Media (GPU diverse) | Alta (emulatore, tempo) |
Golden vs Screenshot — golden test per verificare i singoli componenti UI (pulsante, carta, finestra di dialogo) a ogni commit. Test screenshot per la verifica E2E di interi schermi prima del rilascio. I golden test forniscono un feedback rapido allo sviluppatore, i test screenshot danno fiducia nell’integrità dell’intera applicazione. In IT Sectr utilizziamo golden test per i Pull Request (3–5 minuti) e test screenshot notturni (30–60 minuti).
Paparazzi — una libreria di Cash App (Square) che renderizza componenti Android View e Jetpack Compose in PNG senza emulatore. Utilizza Layoutlib (lo stesso motore di Android Studio Preview). Configurazione: aggiungere il plugin Gradle, scrivere un test con @Test e @RunWith(PaparazziRule::class), chiamare paparazzi.snapshot(view). Paparazzi non supporta animazioni, video o dispositivi reali — solo rendering statico dei componenti.
// build.gradle.kts (module)
plugins {
id("app.cash.paparazzi") version "1.3.1"
}
// Golden test per il componente 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 — un’alternativa a Paparazzi con supporto per Compose, View e confronto immagini. Differenza: Roborazzi funziona tramite Robolectric e supporta una soglia (percentuale ammissibile di differenza pixel). Ciò riduce l’instabilità con GPU diverse su CI. Roborazzi può anche creare animazioni GIF delle modifiche (prima/dopo/diff), comodo per la revisione del codice. Formato file: PNG + metadati JSON.
Aggiornamento del golden — dopo una modifica intenzionale dell’UI, lo sviluppatore elimina i vecchi file golden ed esegue i test con il flag record. Paparazzi ricrea tutti i file golden. Quindi lo sviluppatore committa i nuovi file golden insieme alla modifica del codice. Nella revisione del codice, il revisore vede il diff dei file golden vecchi e nuovi. Se le modifiche vengono approvate — il PR viene unito. In caso contrario — lo sviluppatore corregge il codice e riavvia i test. Non aggiornare mai i file golden automaticamente su CI — solo localmente.
SwiftSnapshotTesting — una libreria di pointfree.co, creatori di Composable Architecture. Supporta UIView, UIViewController, CALayer e SwiftUI View. Principio: assertSnapshot(matching: view, as: .image). Al primo avvio, il golden viene creato automaticamente. Alle esecuzioni successive, viene confrontato. Se la differenza supera la soglia ammissibile, il test fallisce. SwiftSnapshotTesting funziona tramite UIGraphicsImageRenderer, compatibile con 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 (precedentemente FBSnapshotTestCase) — una libreria di Uber per UIKit. A differenza di SwiftSnapshotTesting, iOSSnapshotTestCase richiede di specificare la dimensione e l’orientamento dello schermo. I file golden sono PNG nella cartella ReferenceImages. Vantaggio: funziona con UIKit senza SwiftUI e supporta iOS 12+. Svantaggio: non aggiorna automaticamente i golden — deve essere eseguito con il flag record. SwiftSnapshotTesting è più moderno e consigliato per nuovi progetti.
Golden specifici per dispositivo — i file golden differiscono per diverse dimensioni e orientamenti dello schermo. L’approccio standard: denominare i file golden come TestName@3x~iPhone14.png. SwiftSnapshotTesting aggiunge automaticamente un suffisso del dispositivo se viene specificato il parametro .image(on: .iPhoneSe). Su Android, Paparazzi utilizza DeviceConfig per impostare la dimensione. Archivia i golden per ogni fattore di forma del dispositivo supportato separatamente. Non utilizzare un unico golden per dimensioni diverse — ciò porterà a test instabili.
Pipeline CI — i golden test devono essere eseguiti su ogni Pull Request. Se un test fallisce, il CI mostra l’immagine diff come artefatto di build. Lo sviluppatore esamina il diff e prende una decisione. Importante: i file golden generati su CI non vengono mai committati automaticamente. Solo generazione locale da parte dello sviluppatore dopo una modifica intenzionale. GitHub Actions e GitLab CI supportano il caricamento di artefatti (png, html) per visualizzare i diff nel browser.
Dimensione del repository — i file golden crescono rapidamente. 500 test = 100–400 MB di PNG. Soluzioni: (1) Git LFS — ogni golden viene archiviato in LFS, clonato solo al checkout. (2) Archiviare i golden in un repository separato e includerli come sottomodulo. (3) S3 + caching — golden su S3, CI scarica solo i file modificati per checksum. In IT Sectr utilizziamo Git LFS con track *.png filter=lfs diff=lfs merge=lfs text=false. Localmente, i golden si trovano in src/test/goldens/.
Revisione del codice dei golden — il normale git diff non mostra le modifiche PNG. Soluzioni: (1) GitHub apre le immagini PNG al clic. (2) Utilizzare Review Apps dove i diff golden sono visibili nel browser. (3) Generare un report HTML con colonne prima/dopo/diff. Paparazzi crea un report HTML con tre colonne: effettivo, previsto, diff. Il report viene allegato agli artefatti CI. I revisori visualizzano il report senza scaricare file localmente.
Quando aggiornare il golden — solo dopo una modifica consapevole dell’UI. Modifica di font, colore, padding, icona — il golden deve essere aggiornato. Aggiunta di un nuovo pulsante, riorganizzazione degli elementi — il golden deve essere aggiornato. Una correzione di bug che modifica l’aspetto visivo — il golden deve essere aggiornato. Refactoring senza modifiche all’UI — il golden non deve cambiare. Se un golden cambia senza modifiche al codice UI — è un test instabile causato dall’ambiente, cercare la causa negli agenti CI o nelle versioni delle dipendenze.
Domande frequenti
Golden Test — un test snapshot a livello di componente in un ambiente di test unitario (veloce, senza emulatore). Screenshot Test — cattura l’intero schermo su un dispositivo o emulatore (più lento, ma realistico). Golden funziona con buffer fuori schermo, screenshot con un display reale. Golden è adatto per CI a ogni commit, screenshot per esecuzioni notturne prima del rilascio.
Cause principali: (1) GPU diverse su CI — utilizzare agenti CI identici. (2) Versioni di font diverse — fissare la versione del SO. (3) Anti-aliasing diverso — configurare una soglia (Roborazzi, iOSSnapshotTestCase). (4) Animazioni — disabilitare le animazioni nei test. (5) Elementi di sistema (barra di stato) — utilizzare una configurazione del dispositivo senza bordi. Paparazzi non è soggetto a instabilità grazie a Layoutlib.
Sì. Paparazzi ha il supporto integrato per Compose tramite paparazzi.snapshot { }. Anche Roborazzi supporta Compose. Su iOS, SwiftSnapshotTesting funziona con SwiftUI tramite UIHostingController. I componenti Compose vengono renderizzati tramite Layoutlib, SwiftUI tramite rendering UIKit. Limitazione: le animazioni di Compose e SwiftUI non sono supportate — il golden test cattura solo lo stato iniziale.
Non automatizzare mai l’accettazione dei golden su CI. Solo localmente: lo sviluppatore elimina i vecchi file golden dalla directory ed esegue i test con il flag record (Paparazzi: record=true, SwiftSnapshotTesting: record=true). I file golden vengono ricreati. Lo sviluppatore verifica ogni golden per correttezza, committa le modifiche insieme al codice. L’accettazione automatica su CI porterà a bug UI non rilevati.
I golden test sono più veloci dei test strumentati (UI Automator, XCUITest). Un golden test viene eseguito in 50–200 ms (Paparazzi: 100–150 ms su un MacBook Pro medio). 500 golden test = 25–100 secondi. Confronta con i test screenshot tramite emulatore: 5–30 secondi per test. I golden test non rallentano la compilazione: 100 test = ~15 secondi, accettabile per la verifica pre-merging.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche