Le test de snapshot est une méthode de vérification automatisée de l'interface utilisateur où l'état actuel de l'écran est comparé à une image de référence (snapshot) sauvegardée lors de l'exécution précédente du test. Toute divergence visuelle est enregistrée comme un changement nécessitant la confirmation du développeur. Contrairement aux tests d'UI qui vérifient la présence d'éléments, les tests de snapshot détectent les changements au niveau du pixel — décalages, écarts de couleur et problèmes de mise en page. Selon Android Developers, 2024, le test de snapshot détecte jusqu'à 30 % des régressions visuelles manquées par les tests d'UI traditionnels, ce qui en fait un outil indispensable pour maintenir une interface cohérente.
Points clés
Le test de snapshot est une technique où un test rend un composant d'interface, sauvegarde l'image résultante comme référence, et lors des exécutions suivantes compare le rendu actuel avec cette référence. Si les images correspondent, le test réussit. Si des différences sont trouvées, le test échoue et le développeur reçoit une image diff avec les pixels modifiés en surbrillance. La technique est empruntée au développement web (Jest snapshots) et adaptée aux plateformes mobiles.
La principale valeur des tests de snapshot est la détection automatique des changements visuels inattendus. Un développeur peut modifier la palette de couleurs dans un thème global et affecter accidentellement une douzaine d'écrans. Les tests d'UI qui vérifient la présence de boutons et de textes ne le remarqueront pas. Un test de snapshot capturera chaque changement de pixel sur chaque écran affecté, fournissant une image complète de l'impact du changement.
Selon l'enquête du Mobile DevOps Summit 2023, les équipes qui utilisent les tests de snapshot en complément des tests d'UI classiques réduisent le nombre de défauts visuels dans les versions de 40 %. Cette approche est particulièrement efficace dans les projets avec des systèmes de design et des architectures basées sur des composants, où la modification d'un composant de base peut affecter des dizaines d'écrans de l'application.
La différence fondamentale réside dans l'objet de vérification. Les tests d'UI vérifient la présence, l'état et le comportement des éléments de l'interface : « le bouton est visible », « le texte contient un message d'erreur », « après appui, un nouvel écran s'ouvre ». Les tests de snapshot vérifient l'apparence visuelle complète : positionnement des éléments, marges, couleurs, polices, ombres et coins arrondis. Un test de snapshot répond à la question « l'écran ressemble-t-il à ce qui est attendu ? », tandis qu'un test d'UI répond à « l'écran fonctionne-t-il comme attendu ? »
La vitesse d'exécution diffère également. Les tests d'UI s'exécutent sur un émulateur ou un appareil réel, nécessitent le chargement complet de l'application et prennent de 10 secondes à une minute par scénario. Les tests de snapshot avec des bibliothèques comme Paparazzi rendent les composants dans un environnement virtuel sans lancer d'émulateur, réduisant le temps de test à 100–500 millisecondes. Un ensemble complet de tests de snapshot (50–100 écrans) s'exécute en 2–5 minutes au lieu de 30–60 minutes pour un ensemble comparable de tests d'UI.
Cependant, les tests de snapshot ne remplacent pas les tests d'UI. La stratégie optimale est une combinaison : les tests de snapshot couvrent la régression visuelle (rendu de chaque écran dans les états de base), tandis que les tests d'UI couvrent les aspects comportementaux (scénarios de clic, validation des entrées, navigation). Cette combinaison offre 90 % de confiance dans la correction de l'interface avec un temps d'exécution CI minimal.
Sur Android, les principaux outils sont Paparazzi et Shot. Paparazzi de Cash App rend les composants dans un environnement de test JVM sans émulateur, en utilisant la mise en page par gravité Layoutlib. Shot de Karumi prend des captures d'écran d'Instrumentation sur un appareil réel ou un émulateur et les compare aux références via la bibliothèque AShot, en tenant compte des différences de résolution et de densité de pixels.
Paparazzi ne nécessite pas de lancer d'émulateur — le rendu est effectué sur la JVM via Layoutlib, offrant une vitesse comparable aux tests unitaires. La bibliothèque prend en charge à la fois le système View et Jetpack Compose. Pour Compose, utilisez le modificateur paparazzi.snapshot { MyComposable() }. Les références sont stockées dans src/test/snapshots et sont automatiquement comparées à chaque exécution. Le pourcentage maximal de différence est configurable via maxPercentDifference.
SnapshotTesting de Point-Free prend en charge la comparaison non seulement d'UIImage, mais aussi de chaînes, JSON, Data et de stores Core Data entiers. Cela en fait un outil polyvalent non seulement pour les snapshots d'UI, mais aussi pour vérifier la sérialisation et le décodage des réponses JSON. Pour SwiftUI, utilisez l'extension assertSnapshot avec le modificateur .image(on: .iPhone13). La stratégie record: true crée des références lors du premier lancement.
Pour React Native, la solution populaire est react-native-testing-library combinée avec jest-image-snapshot. L'approche web des tests de snapshot est transposée dans l'environnement mobile en rendant les composants dans un environnement Node.js, suivi de la comparaison des snapshots JSON du DOM virtuel. Cette approche est plus rapide que l'approche native, mais moins précise — elle ne tient pas compte des particularités de rendu des polices et des composants système propres à chaque plateforme. Pour Flutter, les tests golden sont utilisés via le toolkit goldens.
Examinons les tests de snapshot pour Android (Paparazzi) et iOS (SnapshotTesting). Les deux exemples vérifient l'apparence d'un composant — une carte utilisateur avec avatar, nom et statut. Le test rend le composant avec des données de test et compare le résultat à une image de référence stockée dans le dépôt.
Paparazzi utilise l'annotation @Test et la méthode snapshot() pour capturer le rendu. Les références sont sauvegardées dans le dossier src/test/snapshots et sont automatiquement chargées lors de l'exécution suivante pour comparaison.
class UserCardSnapshotTest {
@get:Rule
val paparazzi = Paparazzi(
theme = "Theme.MyApp",
maxPercentDifference = 0.1
)
@Test
fun userCard_defaultState() {
val card = UserCard(
name = "Alice Johnson",
status = "Online",
avatarUrl = "https://example.com/avatar.png"
)
paparazzi.snapshot(card)
}
@Test
fun userCard_offlineState() {
val card = UserCard(
name = "Bob Smith",
status = "Offline",
avatarUrl = null
)
paparazzi.snapshot(card, name = "user_card_offline")
}
}
SnapshotTesting utilise le modificateur .snapshot() dans assertSnapshot. La bibliothèque détermine automatiquement le format — UIImage pour UIView, String pour le texte, Data pour les données binaires.
import SnapshotTesting
import XCTest
class UserCardSnapshotTests: XCTestCase {
func testUserCardDefaultState() {
let card = UserCardView(
name: "Alice Johnson",
status: "Online",
avatarURL: URL(string: "https://example.com/avatar.png")
)
let controller = UIHostingController(rootView: card)
assertSnapshot(matching: controller, as: .image(on: .iPhone13))
}
func testUserCardOfflineState() {
let card = UserCardView(
name: "Bob Smith",
status: "Offline",
avatarURL: nil
)
assertSnapshot(matching: card, as: .image(on: .iPhone13))
}
}
Un flux de travail typique comprend quatre étapes. Première exécution (mode record) : tous les tests de snapshot sont exécutés en mode d'enregistrement — les images de référence sont créées et sauvegardées dans le dépôt. Cette étape est effectuée lors de la configuration initiale des tests ou après un changement intentionnel de l'interface. Après l'enregistrement, les références sont commitées avec le code — elles font partie intégrante du projet.
Lors des exécutions suivantes, les tests fonctionnent en mode de comparaison : chaque nouveau rendu est comparé à la référence. Si des différences sont trouvées, une image diff est générée : les pixels correspondant à la référence sont surlignés en vert, ceux qui diffèrent en rouge. Le développeur étudie le diff et prend une décision : si le changement est attendu (modification de design consciente), la référence est mise à jour avec la commande record ; si inattendu, le bug est corrigé. La mise à jour des références s'effectue avec une seule commande : pour Paparazzi c'est `./gradlew recordPaparazzi`, pour SnapshotTesting — `assertSnapshot(record: true)`.
Selon le Spotify Engineering Blog (2022), les équipes utilisant le flux de travail décrit consacrent en moyenne 2 minutes par test à l'analyse des images diff. Avec un ensemble de 50 tests de snapshot, un cycle complet de mise à jour des références prend 15 à 20 minutes, ce qui est nettement plus rapide que la vérification manuelle des changements visuels sur 50 écrans.
Les tests de snapshot ont des limitations fondamentales. Sensibilité à l'environnement : un même composant peut être rendu différemment selon les versions d'OS, les densités d'écran et les configurations de polices. Des références créées sur une machine peuvent différer du rendu sur un serveur CI. La solution consiste à utiliser des paramètres d'environnement fixes : une version spécifique de Layoutlib pour Paparazzi ou un modèle d'appareil exact pour SnapshotTesting.
Anti-patron n°1 : snapshots géants — un test de snapshot qui capture tout l'écran échoue à chaque modification minime d'un composant. L'approche correcte consiste à tester les composants individuels (bouton, carte, champ de saisie) de manière isolée. Chaque composant est testé indépendamment, ce qui permet d'identifier précisément la source du changement. Anti-patron n°2 : ignorer les diffs — la mise à jour automatique des références sans analyse des images diff réduit la valeur des tests de snapshot à zéro. Chaque diff nécessite une décision consciente du développeur.
Selon le Better Engineering Blog (2023), les tests de snapshot apportent la plus grande valeur lorsqu'ils couvrent les composants du système de design et les écrans clés dans des états de base — vide, rempli, erreur et limite. Couvrir les animations et les états dynamiques avec des tests de snapshot est inefficace en raison de la nature non déterministe des horodatages dans le rendu — pour ces scénarios, l'enregistrement vidéo ou la vérification manuelle QA sont plus adaptés.
Questions fréquentes
Non, les tests de snapshot vérifient l'apparence visuelle, tandis que les tests d'UI vérifient le comportement de l'interface. La stratégie optimale est de combiner les deux approches : les snapshots pour la régression visuelle, les tests d'UI pour les scénarios et la navigation. Les snapshots répondent à « est-ce que ça ressemble ? », les tests d'UI à « est-ce que ça fonctionne ? ».
Les références sont mises à jour à chaque changement de design conscient : nouvelle couleur de thème, marges modifiées, ajout ou suppression d'éléments. La mise à jour s'effectue via le mode record, après quoi les images diff sont examinées lors de la revue de code pour s'assurer que les changements correspondent aux attentes du designer.
En premier lieu, les composants du système de design — boutons, cartes, champs de saisie, fenêtres modales. Ensuite, les écrans clés dans les états de base. Ne testez pas avec des snapshots les animations, WebView, les cartes et les écrans avec contenu dynamique — les snapshots produisent des faux échecs en raison du non-déterminisme.
Utilisez le même niveau d'API pour les modes record et test. Pour Paparazzi, spécifiez une version particulière de Layoutlib dans la configuration. Pour SnapshotTesting, fixez le modèle d'appareil. Les références créées sur Android 14 peuvent différer du rendu sur Android 12 en raison des modifications des polices système et du thème Material.
En CI, les tests de snapshot s'exécutent en mode vérification (verify). Si un test échoue, le CI affiche l'image diff dans les artefacts de build. Le mode record (mise à jour des références) est exécuté localement par le développeur ou dans une tâche CI distincte avec déclenchement manuel. Les images de référence doivent être commitées dans le dépôt.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi