Automatisation de tests · QA de bout en bout
Automatisation des tests d'une application de covoiturage
Une stratégie de test et une suite de bout en bout sur une application web de covoiturage, de l'analyse des exigences au suivi des anomalies.
Une activité QA complète sur une application web de covoiturage : analyse des exigences convertie en stratégie de test, plans de test et jeux de données, un framework Selenium de bout en bout fondé sur les page objects et la synchronisation explicite, une couche Postman sur l'API REST, des campagnes de régression en GitLab CI et un suivi des anomalies dans Jira.
Problème
La valeur d'une application de covoiturage réside dans des parcours qui traversent plusieurs fonctionnalités à la fois : un passager rejoint un trajet, le conducteur confirme, le trajet se termine, et c'est seulement alors qu'une dette apparaît entre deux personnes. Des tests unitaires de part et d'autre de l'API ne peuvent pas atteindre cela. Les tests de bout en bout le peuvent, mais ce sont aussi les premiers qu'une équipe supprime : ils cassent à chaque changement de balisage et échouent par intermittence sur les mises à jour asynchrones.
Objectifs
- Dériver la stratégie de test des exigences et des spécifications fonctionnelles, pour que la couverture soit décidée par ce que le produit a promis et non par ce que le code expose.
- Prouver de bout en bout les parcours qui comptent, plutôt que les unités de part et d'autre de l'API.
- Couvrir les domaines où une régression est visible par l'utilisateur : authentification, véhicules, trajets, amis et dettes.
- Rendre la suite assez maintenable pour survivre aux évolutions de l'interface au lieu d'être supprimée après la première refonte.
- La rendre assez fiable pour être digne de confiance en CI, car une suite qui échoue par intermittence cesse d'être lue.
Mise en œuvre
- Départ depuis les exigences et l'analyse fonctionnelle : une stratégie de test nommant ce qui doit être couvert et à quelle profondeur, puis les plans de test, les cas de test et les jeux de données associés — rédigés avant l'automatisation, pour que celle-ci ait une spécification à satisfaire.
- Page Object Model : chaque écran possède ses sélecteurs et expose des méthodes dans le langage de l'intention utilisateur, si bien qu'un test se lit comme un parcours et qu'un changement de balisage se corrige dans un seul fichier.
- Composants réutilisables pour les éléments récurrents entre écrans, afin de modéliser une seule fois l'interface partagée au lieu de la redécrire dans chaque page object.
- Attentes explicites liées à la condition précise dont dépend chaque étape. Une application monopage se met à jour de façon asynchrone ; une pause fixe est à la fois trop longue sur une machine rapide et trop courte sur une machine lente, ce qui coûte du temps et de la confiance.
- Cas pilotés par les données : une définition de parcours exercée sur plusieurs jeux d'entrées, séparant ce qui est testé de ce avec quoi on le teste — ajouter un cas revient à ajouter une donnée, pas du code.
- Assertions portées sur ce que l'interface affiche après l'action plutôt que sur un état interne, car c'est ce qu'un utilisateur remarquerait en cas de panne.
- Une collection Postman couvre l'API REST comme couche distincte : une rupture de contrat est détectée sans passer par l'interface, et un échec côté UI peut être attribué au frontend ou au backend au lieu d'être supposé.
- Les campagnes fonctionnelles et de régression s'exécutent en GitLab CI, et les résultats, anomalies et campagnes de tests sont consignés dans Jira, si bien qu'un défaut dispose d'une trace du cas en échec jusqu'à sa correction.
Architecture
Stratégie de test
- requirements analysis
- functional specifications
- test plans
- test cases
- data sets
Framework de test
- Selenium WebDriver
- browser session
- Page Object Model
- reusable components
- explicit waits
- UI-level assertions
- pytest fixtures
- data-driven cases
Suites
- authentication
- vehicles
- trips
- friends
- debts
- key journeys
- Postman REST collections
Intégration continue
- GitLab CI
- functional + regression runs
- Jira: anomalies & test campaigns
Technologies
- Selenium
- WebDriver
- Python
- Pytest
- Page Object Model
- Postman
- GitLab CI
- Jira
Difficultés & solutions
Difficulté
Les suites de bout en bout finissent souvent abandonnées, non parce qu'elles ne trouvent rien, mais parce que chaque évolution de l'interface casse des dizaines de tests d'un coup.
Solution
Confiner la connaissance des sélecteurs aux page objects. Le coût d'une refonte évolue alors avec le nombre d'écrans modifiés, et non avec le nombre de tests qui les traversaient.
Difficulté
Les mises à jour asynchrones font échouer par intermittence les tests naïfs, et une suite instable est vite ignorée — ce qui est pire que pas de suite du tout.
Solution
Attendre des conditions, jamais l'horloge. Chaque étape se bloque jusqu'à ce que l'état requis soit réellement présent : plus rapide qu'une pause prudente, plus fiable qu'une pause optimiste.
Difficulté
La logique des dettes est celle dont un bug coûte le plus, puisqu'il s'agit d'argent entre personnes, et elle n'est observable qu'au terme d'un parcours en plusieurs étapes.
Solution
L'exercer comme un parcours traversant plusieurs écrans plutôt que comme une vérification isolée, pour que l'assertion porte sur l'état qu'un utilisateur verrait et contesterait.
Difficulté
Une suite qui répète le même flux pour chaque jeu d'entrées devient ingérable bien avant d'être complète.
Solution
Piloter les cas par les données : la couverture s'étend en ajoutant des lignes plutôt qu'en dupliquant des fonctions de test.
Difficulté
Un test de bout en bout en échec prouve que quelque chose est cassé, mais pas où, et remonter un symptôme d'interface jusqu'au backend est la façon la plus lente de le découvrir.
Solution
Tester l'API REST séparément avec Postman. Si la couche API passe et que l'UI échoue, la faute est au frontend ; si les deux échouent, non. La seconde couche se rentabilise en temps de diagnostic.
Résultats
- Les cas de test remontent aux exigences et non à l'implémentation : la suite dit ce que l'application était censée faire au lieu de reformuler ce qu'elle fait déjà.
- Deux couches plutôt qu'une : Postman sollicite directement l'API REST, ce qui localise une rupture de contrat côté backend en quelques secondes, tandis que la suite Selenium prouve le parcours réellement suivi par un utilisateur.
- Six domaines fonctionnels sont exercés à travers l'interface réellement utilisée, y compris les parcours liés à l'argent, là où une régression coûte le plus cher.
- La connaissance des sélecteurs vit dans les classes de page : renommer un élément devient une modification d'une ligne plutôt qu'une reprise de toute la suite.
- Attendre une condition plutôt que le temps qui passe supprime les échecs intermittents qui font qu'une suite finit par être ignorée — c'est ce qui décide si elle a le droit de bloquer une fusion.
Enseignements
- Rédiger le plan de test avant l'automatisation change ce qui est automatisé. Partir des exigences a fait émerger des cas qui ne me seraient jamais venus en lisant le code, car le code ne peut pas dire ce qu'il était censé faire.
- Le véritable ennemi d'une suite de tests est son coût de maintenance, pas sa couverture manquante. L'indirection du Page Object Model se paie justement parce qu'elle décide si la suite survit à la prochaine refonte.
- Les attentes explicites ne relèvent pas du style. Les pauses fixes arbitrent entre vitesse et fiabilité et perdent sur les deux, or c'est la fiabilité qui donne à une suite le droit de bloquer une fusion.
- Les tests de bout en bout justifient leur coût sur les chemins qui traversent plusieurs fonctionnalités à la fois — précisément là où les tests unitaires, de part et d'autre de l'API, ne voient rien.