# Maîtriser les Golden Tests Flutter avec Alchemist

## Introduction

Lors du développement d’une application mobile, l’interface utilisateur concentre une grande partie des efforts. Au fil de la vie d'un projet, le code change constamment : on corrige des bugs, on refactorise, on fait des montées de version du framework... Le défi majeur est de garantir qu’une modification à un endroit précis n’aura aucun impact visuel négatif sur un écran existant.

Une simple mise à jour d’un thème global, une évolution d’un composant partagé ou un refactoring peuvent entraîner des régressions visuelles parfois très subtiles, mais bien réelles en production. C’est pour répondre à cette problématique précise que les Golden Tests ont été élaborés. Ce guide vous accompagne pas à pas pour comprendre leur fonctionnement et les implémenter facilement à l'aide du package Alchemist.

## En quoi consistent les Golden Tests ?

Pour comprendre l'intérêt d'un Golden Test, il est utile de le comparer aux autres typologies de tests de votre stack :

*   **Les tests unitaires** : Ils valident de manière isolée la logique métier et les algorithmes.
    
*   **Les tests de widgets** : Ils simulent les interactions (clics, scrolls) et valident les comportements de base.
    
*   **Les tests d'intégration** : Ils s'assurent que les différentes parties complexes de l'application fonctionnent correctement ensemble.
    

Cependant, aucun de ces tests ne garantit que l'interface affichée à l'écran est exactement celle attendue.

Exemple concret : Un padding est modifié par erreur de quelques pixels, une couleur issue du thème change subtilement, une police de caractères ne se charge plus correctement ou un bouton perd son rayon de courbure. L'application fonctionne toujours, les tests de widgets passent au vert... mais l'interface visuelle est altérée.

Le principe du Golden Test résout ce problème de manière simple :

1.  Flutter génère dynamiquement une capture d'écran du widget testé.
    
2.  Cette capture est comparée au pixel près à une image de référence validée en amont, appelée le Golden.
    
3.  Si les deux images diffèrent, le test échoue immédiatement, signalant un changement imprévu.
    

## L'avantage d'Alchemist

Bien que Flutter fournisse nativement les outils nécessaires pour écrire des Golden Tests, leur mise en œuvre à grande échelle devient rapidement fastidieuse lorsque les scénarios se multiplient. Il faut en effet configurer un environnement de test cohérent, charger les polices manuellement, stabiliser le rendu visuel selon les machines et écrire beaucoup de code répétitif.

C’est là que le package Alchemist intervient comme une couche d'abstraction simplifiant ces opérations critiques :

*   Créer facilement un environnement de test rigoureusement stable.
    
*   Tester plusieurs variantes d'un même widget au sein d'une seule et unique image.
    
*   Produire des captures homogènes et réduire drastiquement le code boilerplate nécessaire.
    

Le résultat est une expérience beaucoup plus agréable, particulièrement lorsque les composants d'une application deviennent nombreux.

## Installation et Configuration

Pour débuter, ajoutez Alchemist à vos dépendances de développement dans le fichier *pubspec.yaml* :

`dev_dependencies:`

`alchemist: ^0.7.0`

Une configuration unique garantit que les captures générées seront identiques sur toutes les machines. Il est également recommandé d'utiliser un thème dédié aux tests afin d'éviter toute variation liée à la configuration du terminal exécutant les tests.

Ensuite, on configure un environnement de test identique pour tous les développeurs (taille d'écran, thème, polices, densité de pixels) via un fichier unique nommé flutter\_test\_config.dart à la racine du dossier des tests :

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/7be47f85-6c08-48d0-a0eb-54fd2c86a672.png align="center")

## Écrire son premier Golden Test

Une fois la configuration en place, écrire un Golden Test devient intuitif et très expressif. Prenons l'exemple ci-dessous, qui teste simultanément les différentes variantes d'un composant de type bouton personnalisé nommé AppButton :

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/9f56fce8-ed16-461b-a79b-9cb19f0b7b55.png align="center")

Le point d'entrée est la fonction *goldenTest*. Elle utilise un **GoldenTestGroup** pour regrouper différents scénarios (états activé, désactivé, libellé long) dans une seule image de référence. Cette approche limite la multiplication des fichiers et facilite la revue visuelle.

À l'intérieur du builder, on retrouve un GoldenTestGroup. Ce widget permet de regrouper plusieurs scénarios dans une même capture. Chaque scénario est représenté par un GoldenTestScenario, auquel on associe :

*   un name, qui sera affiché sous le widget dans l'image générée ;
    
*   un child, correspondant au widget à tester.
    

Dans cet exemple, quatre variantes du bouton sont testées :

*   un bouton activé (Enabled) ;
    
*   un bouton désactivé (Disabled) ;
    
*   un bouton activé avec un libellé long ;
    
*   un bouton désactivé avec un long libellé.
    

En une seule exécution, Alchemist génère donc une image contenant ces quatre états côte à côte. Cette approche facilite la comparaison visuelle des variantes d'un même composant et limite le nombre de fichiers Golden à maintenir.

Lors de la première exécution, l'image de référence est créée. Les exécutions suivantes comparent automatiquement le rendu actuel avec cette image. Si une différence est détectée, le test échoue, signalant une régression visuelle ou une évolution de l'interface qui mérite d'être vérifiée.

**Attention aux données dynamiques (Dates et Images réseau)**

Dès vos premiers tests, vous allez sûrement rencontrer un défi classique : les éléments qui changent d'une exécution à l'autre. Un test ne doit jamais échouer de manière aléatoire (ce qu'on appelle un *flaky test*). Si le composant que vous testez affiche des données dynamiques, il est impératif de les figer :

*   Les dates et l'heure : Un widget dont le rendu dépend de la date du jour fera systématiquement échouer votre test le lendemain. La meilleure pratique consiste à rendre vos composants prédictibles en leur injectant des dates "en dur" directement via leur constructeur (par exemple : DateTime(2020, 5, 5)). Cependant, si la logique de votre widget nécessite d'évaluer le temps courant (pour afficher "Il y a 2 minutes" par exemple), évitez l'appel à DateTime.now(). Utilisez plutôt le package officiel clock, qui permet de figer virtuellement le temps lors de vos tests avec la fonction withClock(...).
    
*   Les images réseau : L'environnement de test Flutter s'exécute sans accès réseau. Si votre premier composant tente de charger une image via NetworkImage, le test va ralentir ou planter. Pour contourner cela, utilisez un package comme mocktail\_image\_network ou network\_image\_mock. Ces outils interceptent les requêtes et renvoient instantanément une image factice (ou un carré gris) aux bonnes dimensions.
    

Isoler la donnée dynamique dès vos premiers tests est la clé pour construire des images de référence déterministes, garantissant ainsi le succès continu de votre CI/CD.

## Structurer ses tests pour la scalabilité

Dans un projet d'envergure doté d'un Design System composé de dizaines de composants, une organisation rigoureuse est indispensable. Une excellente approche consiste à reproduire fidèlement l'architecture de vos widgets au sein de votre dossier de test test/golden/ :

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/7d8ec642-19af-4b4b-803f-5420206c748d.png align="center")

Chaque catégorie du Design System (molecules, organisms, templates, etc.) possède son propre dossier contenant :

*   les fichiers de tests (\*\_golden\_test.dart) ;
    
*   un sous-dossier goldens/ dans lequel sont générées les images de référence.
    

Cette organisation présente plusieurs avantages :

*   elle reflète la structure des composants de l'application ;
    
*   les tests restent proches des Goldens qu'ils génèrent ;
    
*   les conflits sont limités lorsque plusieurs développeurs travaillent sur des composants différents ;
    
*   retrouver un Golden devient immédiat.
    

À mesure que le Design System évolue, cette organisation reste lisible et facilite la maintenance des tests. Lorsqu'un composant est ajouté, modifié ou supprimé, ses Golden Tests et leurs images de référence se trouvent au même endroit, ce qui simplifie également les revues de code.

## Génération et mise à jour des Goldens

À la création d'un nouveau test, générez les images de référence avec la commande suivante :

`flutter test --update-goldens`

Cette commande crée (ou met à jour) les images de référence (.png) utilisées par les Golden Tests.

Une fois les Goldens générés, il suffit d'exécuter les tests normalement :

`flutter test`

Flutter compare alors le rendu actuel des widgets avec les images de référence. Si une différence est détectée, le test échoue et signale une régression visuelle ou une évolution de l'interface.

Lorsque les modifications sont intentionnelles, il suffit de régénérer les Goldens avec :

`flutter test --update-goldens`

Pour gagner du temps, il est également possible de cibler un seul fichier de tests :

`flutter test --update-goldens test/golden/button_test.dart`

Avant de mettre à jour les Goldens, prenez toujours le temps de vérifier que les différences sont bien attendues. Les images de référence doivent être considérées comme la source de vérité du rendu visuel et être versionnées avec le code.

## Analyse des échecs et Debugging

Dans la partie macos du fichier golden généré nous retrouvons les composants visuels de référence. Dans notre cas, ce sera les différents cas de tests du bouton.

**Référence macOS — goldens/macos/button.png**

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/a0109087-73b9-4efa-bc35-ff0c1588be78.png align="center")

Maintenant, imaginons qu'une modification involontaire survienne dans le fichier button.dart , modifiant la couleur de fond du bouton (du turquoise vers le bleu) :

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/bead341d-e080-48e6-99f7-d6595684cf3d.png align="center")

Le layout reste identique (hauteur, padding, texte). Seule la couleur de fond change — du vert au bleu. Le test échoue immédiatement.

Pour vous guider dans la résolution du problème, Alchemist génère automatiquement des artefacts de diagnostic ultra-précis au sein du dossier failures/ :

**button\_masterImage.png**

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/fda801bf-7609-4805-920d-5ad59b8968ed.png align="center")

Copie de la référence utilisée au moment du failure. Sert de base de comparaison dans le rapport d'erreur. Visuellement identique au golden macOS.

**button\_testImage.png**

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/b05d60f4-e305-4624-abec-9907283eafcf.png align="center")

Rendu actuel produit par le code modifié. Même structure, mêmes labels, mais boutons bleus au lieu de vert.

**button\_isolatedDiff.png**

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/0753b3c4-3ea4-4ec7-affc-4c4f4b23557d.png align="center")

Affiche uniquement les pixels qui diffèrent, sur fond noir. Les zones roses/rouges correspondent aux rectangles des boutons — là où la couleur a changé. Le texte et le fond global n'apparaissent pas car ils sont identiques.

**button\_maskedDiff.png**

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/8232083e-7bd2-402c-94e3-42e90cfd92ca.png align="center")

Comparaison côte à côte : référence à gauche, rendu actuel à droite. Permet de visualiser l'écart sans superposition, scénario par scénario.

Gestion multi-environnements : CI vs macOS

Vous constaterez que les images de référence sont cloisonnées dans deux sous-dossiers spécifiques : macos/ et ci/ .

![](https://cdn.hashnode.com/uploads/covers/6a672fdf465f50023f5cb929/53126db0-4163-48e2-8794-d56ab3d4fc07.png align="center")

Cette séparation permet à Alchemist de gérer les différences de rendu graphique entre les environnements d'exécution.

*   macos/ contient les images générées localement lors de l'exécution des tests sur une machine macOS.
    
*   ci/ contient les images utilisées par le pipeline d'intégration continue (GitHub Actions, GitLab CI, Azure DevOps, etc.), où le rendu est généralement produit sous Linux.
    

Les différences de rendu entre macOS et Linux (souvent utilisé en CI) peuvent provoquer des faux positifs. Alchemist résout ce problème en séparant les images de référence dans des dossiers distincts (*macos/* et *ci/*), garantissant la fiabilité des tests sur chaque plateforme.

Dans la plupart des projets, les développeurs travaillent avec les Goldens du dossier macos, tandis que la CI valide les images présentes dans le dossier ci, garantissant ainsi des tests fiables sur chaque environnement.

## Intégration CI/CD et Bonnes Pratiques

Les Golden Tests sont particulièrement intéressants lorsqu'ils sont exécutés automatiquement dans la chaîne d'intégration continue. Chaque Pull Request peut ainsi vérifier que l'interface n'a subi aucune modification inattendue. Quelques bonnes pratiques permettent de conserver des tests fiables :

*   utiliser les mêmes versions de Flutter sur toutes les machines ;
    
*   figer les polices utilisées ;
    
*   éviter les widgets dépendants de la date ou de l'heure ;
    
*   supprimer les animations ou les stabiliser avant la capture ;
    
*   tester des composants isolés plutôt que des écrans complets lorsque cela est possible ;
    
*   Versionner les images générées avec le code source.
    

Dans un pipeline CI/CD, les Golden Tests deviennent un véritable filet de sécurité avant chaque livraison.

Ils permettent également de faciliter les revues de code, puisqu'un changement visuel est immédiatement détectable.

## Conclusion

Les Golden Tests sont le complément indispensable des tests logiques pour assurer la qualité d'une application Flutter. En adoptant Alchemist, vous transformez une tâche complexe en un processus fluide et automatisé, protégeant durablement l'intégrité visuelle de votre application.

Cette approche de validation visuelle n'est d'ailleurs pas exclusive à Flutter. Elle s'inscrit dans une tendance globale de l'ingénierie front-end visant à fiabiliser les Design Systems face aux régressions. Si vous ou vos équipes évoluez sur d'autres stacks technologiques, le même concept (souvent appelé *Snapshot Testing*) s'applique avec des outils tout aussi matures :

*   **En natif iOS (Swift / SwiftUI) :** La librairie [swift-snapshot-testing](https://github.com/pointfreeco/swift-snapshot-testing) (créée par Point-Free) est la référence absolue pour générer des références visuelles de vos UIView ou vues SwiftUI.
    
*   **En natif Android (Kotlin / Jetpack Compose) :** Des outils très puissants comme [Paparazzi](https://github.com/cashapp/paparazzi) (par Cash App) ou [Roborazzi](https://github.com/takahirom/roborazzi) permettent de faire du rendu de composants et de capturer des écrans sans même avoir besoin de lancer un émulateur.
    
*   **En React Native :** L'écosystème s'appuie fréquemment sur des extensions de Jest, comme le plugin [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot), pour comparer le rendu visuel des composants au pixel près.
    

Que ce soit avec Flutter via Alchemist ou sur d'autres plateformes avec ces alternatives, l'intégration continue de tests visuels est aujourd'hui un investissement extrêmement rentable. C'est la garantie de livrer des interfaces parfaites et d'offrir une expérience utilisateur sans faille, mise à jour après mise à jour.

## Sources et pour aller plus loin

**Articles de référence sur les Golden Tests**

*   **LeanCode** : [Golden Tests in Flutter: Common Mistakes, Best Practices](https://leancode.co/glossary/golden-tests-in-flutter)
    
*   **SolGuruz** : [Flutter Golden Tests: Catch UI Bugs Before They Reach Users](https://solguruz.com/blog/flutter-golden-tests/)
    

**Packages de l'écosystème Flutter**

*   **Alchemist** : [Lien](https://pub.dev/packages/alchemist) [pub.dev](http://pub.dev) – Le package détaillé dans ce guide pour simplifier la création des Golden Tests.
    
*   **Golden Toolkit** : [Lien](https://pub.dev/documentation/golden_toolkit/latest/) [pub.dev](http://pub.dev) – L'alternative historique créée par eBay.
    
*   **Clock** : [Lien](https://pub.dev/packages/clock) [pub.dev](http://pub.dev) – L'utilitaire officiel pour mocker et figer le temps lors de l'exécution des tests.
    

**Le Snapshot Testing sur les autres technologies**

*   **Apple (iOS / macOS)** : [swift-snapshot-testing](https://github.com/pointfreeco/swift-snapshot-testing) – La librairie de référence par Point-Free.
    
*   **Android Natif** :
    
    *   [Paparazzi](https://github.com/cashapp/paparazzi) – Rendu et capture sans émulateur par Cash App.
        
    *   [Roborazzi](https://github.com/takahirom/roborazzi) – Alternative moderne couplée à Robolectric.
        
*   **React Native & Web** : [jest-image-snapshot](https://github.com/americanexpress/jest-image-snapshot) – Le plugin Jest maintenu par American Express.
