Tests FIRST

Test automatisé

Fast / Isolated / Repeatable / Self-validating / Timely

Test automatisé

Description

Le scriptage des tests pour automatiser les tests n'est pas suffisant car 

  • le scripting ne concerne que les cas de test, tandis que les cas de test ne sont pas des tests [Bach 2014].
  • si vos scripts introduisent une complexité supplémentaire à votre solution, ils seront mis de côté et la qualité de la solution diminuera.

Cependant, 

  • les tests sont inévitables et l'approche Agile/DevOps préconise une automatisation massive pour compenser les tests manuels
  • pour réduire la complexité des scripts de test, leur ingénierie doit être "FIRST".

FIRST est un acronyme qui signifie [Martin 2008] :

  • "Rapide" : les tests doivent s'exécuter rapidement pour obtenir un retour d'information rapide et facile, afin que l'exécution du script de test fasse facilement partie de l'activité de développement ; en outre, lorsqu'ils sont intégrés à un pipeline, il faut garder à l'esprit que l'ensemble du processus C/CD doit durer moins de 10 minutes.
  • "Indépendant" : Les tests ne doivent pas dépendre les uns des autres. Vous devriez être en mesure d'exécuter chaque test indépendamment et d'exécuter les tests dans n'importe quel ordre. C'est probablement pour cela que certains auteurs nomment cette caractéristique "Isolé" [Ottinger 2009] et éventuellement "Hermetic test pattern" ou "Test is an Island Pattern" [Kovalenko 2014].
  • "Répétable" : Les tests doivent pouvoir être répétés à tout moment, dans n'importe quel environnement.
  • "Autovalidation" : Les tests doivent avoir une sortie booléenne. Aucune interprétation ne doit être requise, ils passent ou échouent. 
  • "En temps opportun" : Les tests doivent être écrits en temps utile, le plus tôt étant le mieux, même avant le code de production.

FIRST diffère de "Test First" qui est une pratique XP [Beck 2004]. En fait, puisque le "Timely" fait partie de FIRST, les développeurs devraient pratiquer "Test First" et ensuite TDD sur une base régulière.

FIRST n'est pas la seule façon de penser à l'amélioration de votre approche des tests.

Par exemple, nous avons un autre acronyme donné par Andrew Hunt quelques années avant FIRST avec "Good tests are A TRIP" [Hunt 2003] :

  • Automatique: les tests doivent être exécutés systématiquement et (éventuellement) automatisés.
  • Rigueur: il ne faut pas seulement effectuer les principaux tests, mais aussi les tests de coin.
  • Répétable: si elle est exécutée plusieurs fois, le résultat doit rester inchangé.
  • Indépendant: les tests ne dépendent pas des autres.
  • Professionnel: la qualité des tests doit être aussi élevée que possible pour l'équipe, compte tenu de l'état de l'art - La communauté de pratique et les pratiques de Software Craftsmanship devraient favoriser le professionnalisme au sein de l'équipe.

Il y a aussi "FAST" [Ferguson 2017] [Moustier 2019-1] :

  • Rapide: pour livrer rapidement, les tests doivent être rapides.
  • Actionnable: les tests défaillants peuvent être isolés et traités pour être corrigés.
  • Évolutif: plus vous avez de tests, plus vous aurez de travail, à moins qu'ils ne soient faciles à maintenir, notamment lorsque l'application change et que des faux positifs apparaissent. Les changements doivent être aussi fluides que possible.
  • Digne de confiance: Avant tout, vous devez avoir une bonne confiance dans vos tests ; sinon, la valeur ajoutée perçue des scripts de test diminuera et l'automatisation des tests sera abandonnée.

Ces propositions prennent en compte la rapidité du processus de livraison, y compris les tests, et la qualité des scripts de test sous-jacents à l'échelle.

Impact sur la maturité des tests

Même dans des contextes simples, lorsqu'il y a une quantité énorme de tests, il peut devenir délicat de gérer l'automatisation des tests ; le fait est que le développement de logiciels implique des contextes complexes [Snowden 2007]. Lorsqu'il y a une quantité massive de scripts de test combinée à un environnement complexe, le FIRST ne suffit pas, il faut "Gardez vos tests propres" - [Martin 2008].

Le problème est que les tests doivent changer au fur et à mesure que le code de production évolue. Plus les tests sont sales, plus ils sont difficiles à modifier. En conséquence, ils deviendront de plus en plus inutilisables et finiront par générer des plaintes [Martin 2008]. Cela se produit dans les équipes matures parce que, sans une suite de tests fiable, l'équipe ne peut pas garantir que les changements apportés à une partie de son système ne casseront pas d'autres parties de son système : les équipes immatures laisseront les scripts pourrir puis un effet de "fenêtre brisée" s'installe et la dette technique augmente. Si vous laissez les tests pourrir, alors votre code pourrira aussi. L'approche dite "Clean Test" de Robert C. Martin préconise que les scripts de test doivent rester flexibles, maintenables et réutilisables pour s'adapter aux changements du code de production [Martin 2008].

La différence théorique entre le scripting et le codage est que les langages de scripting ne nécessitent pas l'étape de compilation et sont plutôt interprétés [GeeksforGeeks 2022] [softwaretestinghelp 2022]. En fait, le codage est un genre, le scriptage est un sous-genre [Morris 2022]. Cela implique de traiter les scripts comme du code et de les laisser compréhensibles, puis d'adopter le langage spécifique au domaine (DSL) qui convient au contexte. Des outils tels que Gherkin comblent le fossé entre la question du DSL au niveau de l'histoire de l'utilisateur (US) avec un langage de développement, et les tests unitaires au niveau du code qui "parlent" le langage des développeurs, conformément au développement piloté par le domaine. Le fossé entre ces niveaux d'abstraction et les domaines peut être comblé, par exemple, en combinant ATDD et TDD. Ce lien entre le macro et le micro a été abordé sous le terme "apprentissage en double boucle" [Argyris 1977] [Smith 2001]. Il permet de centrer l'organisation sur le client et utilise les tests comme un ciment. Le fait de disposer de tests FIRST facilite l'apprentissage en double boucle grâce à un retour d'information rapide et déterministe.

Cependant, lorsque les tests deviennent plus macroscopiques, ils sont plus difficiles à gérer, notamment en ce qui concerne les données de test, ce qui entrave généralement la répétabilité. Les outils disponibles permettent d'automatiser les nombreux aspects des tests tels que la gestion des tests, les tests de charge, la création de scripts de test, et contribuent à l'automatisation des tests, mais les limites intrinsèques des outils constituent une vitre de plafond qui empêche les tests FIRST d'atteindre un certain niveau.

Comme l'automatisation implique un peu de code, nous pouvons alors voir comment les principes de la conception orientée objet SOLID [Martin 2008] [Metz 2015] pourraient être adaptés aux tests :

  •  Principe deresponsabilité unique (SRP) :"Il ne devrait jamais y avoir plus d'une raison pour qu'une classe change" - la conception devrait vous aider à avoir une seule raison de mettre à jour votre actif ; par conséquent, vous devriez avoir une seule assertion par test et un seul concept par test [Martin 2008].
  • Principe Open-Closed (OCP) :"Les entités logicielles ... doivent être ouvertes à l'extension, mais fermées à la modification" : appliqué aux scénarios de test, il serait préférable d'ajouter des tests au lieu de les mettre à jour, introduisant ainsi des "tests immuables", surtout lorsque votre solution logicielle implique également des composants immuables. Ce paradigme vous conduira à laisser vivre les tests tant qu'une fonctionnalité est en production et à les retirer des suites de tests lorsque la fonctionnalité est déclassée.
  • Principe de substitution deLiskov (LSP) :"Les fonctions qui utilisent des pointeurs ou des références à des classes de base doivent pouvoir utiliser des objets de classes dérivées sans le savoir" - dans la mesure du possible, le test doit être indépendant des détails de l'implémentation et des paramètres de l'environnement tels que les données ou l'infrastructure - il doit fonctionner indépendamment du contexte, dans la mesure du possible.
  •  Principe de ségrégation desinterfaces (ISP) :"Il est préférable de disposer de plusieurs interfaces spécifiques au client plutôt que d'une seule interface à usage général" - les tests devraient reposer sur des interfaces avec 1 assert par test ; ce paradigme fournira de nombreux tests spécifiques à l'interface, mais il faudra ensuite introduire une boucle de rétroaction à un niveau supérieur selon le principe de "l'apprentissage en double boucle" qui s'adapterait aux niveaux d'abstraction avec des modifications appropriées du DSL
  •  Principe d'inversion de ladépendance (DIP) :" Dépendez des abstractions, [pas] des concrétions "."Les tests devraient impliquer les niveaux appropriés d'abstraction avec des outils appropriés pour faciliter la manipulation (par exemple, des outils basés sur Gherkin pour US Critères d'acceptation et un cadre xUnit au niveau du code).

Enfin, les tests doivent faire très attention aux faux positifs, surtout lorsque la qualité est basée sur une stratégie d'automatisation. Pour cela, le pilier Lean nommé "Jidoka" doit faire partie de la stratégie d'automatisation des tests [Moustier 2022].

Par conséquent, vos tests (automatisés) doivent être

  • FIRST
  • SOLIDE
  • Jidoka-driven

Cependant, une telle approche peut s'avérer très délicate lorsque 

  • la quantité de tests devient énorme 
  • il est techniquement difficile à gérer en raison de tests non fondés sur des formulaires avec des interfaces utilisateur graphiques complexes ou lorsqu'il n'y a pas d'interface technique sur laquelle s'appuyer.
  • les changements sur la solution se produisent plus rapidement que l'ingénierie des tests

Dans ces conditions, les tests doivent faire appel à des techniques à la volée telles que les tests exploratoires combinés à des techniques de test de type Shift Left appliquées aux activités d'idéation.

Le point de vue d'Agilitest sur cette pratique

Agilitest recommande la pratique FIRST à tous ses utilisateurs. Puisque l'outil facilite les scripts de test robustes, certains clients ont tendance à générer des cas de test très longs (jusqu'à 3000+ étapes !) avec de multiples points de validation. Mais lorsqu'il s'agit de traçabilité et de couverture des exigences, la production de certains KPI devient difficile et la répétabilité repose alors sur une gestion solide des données de test, sans oublier les caractéristiques d'auto-validation et de ponctualité.

Puisque Agilitest fournit une structure basée sur des dossiers avec des sous-scripts. Il est alors possible de regrouper les scripts selon des niveaux d'abstraction tels que le niveau métier (processus) et le niveau de détail de l'implémentation (écrans) pour rendre les scripts plus lisibles, à condition que les sous-scripts soient nommés de manière cohérente avec le niveau d'abstraction afin de garantir des scripts de test auto-explicatifs. 

La question de l'immuabilité est également abordée avec des ensembles de données de test exploitables même au niveau sous-script pour garantir l'indépendance. Comme ces données peuvent être au format JSON ou CSV, elles peuvent éventuellement être générées par des tiers pour permettre la gestion de la migration des données requise par les changements de version de l'application. Pour renforcer la question de l'immuabilité, Agilitest génère des scripts au format texte, ce qui permet facilement la gestion de la configuration et la gestion de la ligne de base pour correspondre à la version du code de production dans votre pipeline DevOps.

Pour découvrir l'ensemble des pratiques, cliquez ici.

Cartes connexes

Pour aller plus loin

  • [Hunt 2003] : Andrew Hunt & David Thomas - 2003 - " Pragmatic Unit Testing : En Java avec JUnit" - isbn:9780974514017
  • [Kovalenko 2014] : Dima Kovalenko - 2014 - "Patrons de conception et meilleures pratiques de Selenium" - isbn:9781783982714
  • [Martin 2008] : Robert C. Martin - 2008 - "Clean Code a Handbook of Agile Software Craftsmanship" - isbn:9780359582266
  • [Smith 2001] : Mark K. Smith - 2001 (mis à jour en 2005) - "Chris Argyris : théories de l'action, apprentissage en double boucle et apprentissage organisationnel" - www.infed.org/thinkers/argyris.htm 
© Christophe Moustier - 2021