Modèles de typologie de tests
Dans cet article, je vous présente différents modèles qui servent à classifier les différents types de test. Le but de ces modèles est de prendre de la hauteur et comprendre pourquoi définit-on ces différents types de test.
Cout d’exécution & délai de feedback
Un premier modèle consiste à répartir les types de tests par leur cout d’exécution et leur délai de feedback, ces deux paramètres étant souvent liés : plus un test est couteux à mettre en oeuvre, plus son exécution est généralement longue et donc son délai de feedback long.
La pyramide de test Agile
Ce modèle est la base de la pyramide de test Agile de Mike Cohn. (lien à la fin de l’article) En rajoutant une 2e dimension pour le nombre de tests ou l’effort à fournir pour chaque catégorie de test, on obtient une pyramide :
Cette métaphore de la pyramide modélise très bien les atouts d’une stratégie de test automatisée réussie :
- Maximiser les tests qui sont à la fois les moins chers et qui fournissent un feedback le plus rapide possible
- Il faut donc viser une excellente couverture de code par ces tests, qui forment le noyau dur de la stratégie de test
- À l’inverse, minimiser les tests qui sont à la fois les plus couteux et avec le délai de feedback le plus long
- Bien qu’il faille essayer de faire le moins possible de ces tests couteux, il serait dangereux de s’en passer et ils restent nécessaire
Périmètre d’un test
On peut faire une variante de la pyramide de test Agile en se focalisant plutôt sur le périmètre des différents tests. Voici un exemple de catégorisation :
- Fonction : typiquement un test unitaire, le test s’attarde sur une fonction, une classe, un objet
- Composant : le test s’attarde sur un périmètre plus grand que celui d’un test unitaire, tout en restant confiné à l’intérieur d’un composant de l’architecture logicielle
- Multiples composants : le test sort cette fois d’un composant et a un périmètre qui regroupe plusieurs composants
- Bout en bout : le test implique l’intégralité du produit
Ces 4 niveaux sont donnés à titre indicatif. Si vous essayez d’appliquer ce modèle à votre produit, vous aurez plus ou moins de niveaux selon sa complexité et les spécificités de son architecture.
Les réflexions en termes de cout d’exécution et de délai de feedback s’appliquent tout autant à ce modèle. C’est assez logique car plus le périmètre est large, plus il y a de dépendances à prendre en compte et plus l’environnement de test est contraignant :
- Fonction : aucun environnement, le code testé est exécuté en isolation complète
- Composant : le code du composant est lancé intégralement, toutes les dépendances hors du composants sont simulées
- Multiples composants : les composants testés sont lancés intégralement, seules certaines dépendances sont simulées
- Bout en bout : il faut l’équivalent d’un environnement complet, le plus similaire possible à l’environnement de production
Conséquences d’un environnement de test complet
Plus longs à exécuter : Une dépendance simulée répond beaucoup plus vite qu’une réelle dépendance qui doit faire un calcul, effectuer des appels réseaux, accéder à une base de données…
Plus fragiles : Le résultat retourné par une dépendance simulée est complètement déterministe. Une dépendance non simulée peut retourner des résultats variables, ou dépendant de conditions externes non-maîtrisables ou trop coûteuses à maîtriser.
Plus coûteux : Un environnement de test complet utilise des serveurs dédiés le temps du test.
La variante pragmatique de Google
Le livre How Google Tests Software (lien à la fin de l’article) présente une vision alternative qui simplifie la catégorisation des tests : Small, Medium et Large.
En plus de proposer une classification très facile à appréhender, cette approche est très orientée vers les tests automatisés et leur utilisation au sein de l’intégration continue. (lien à la fin de l’article) Google met un accent très prononcé sur l’automatisation et la durée d’exécution d’un test est un élément important de sa classification.
Quand on y regarde de plus près, on voit que ces notions se combinent et dans le cas de Google, le contexte d’exécution du test s’assure même qu’ils sont respectés :
- En fonction de la taille du test, plus ou moins de dépendances sont permises (leur instanciation est programmatiquement interdite selon la taille du test)
- La durée d’exécution d’un test est bornée en fonction de la taille du test
Rôle d’un test
Une autre manière de classer les différentes catégories de test est selon son rôle. Que testent les tests de cette catégorie ?
Voici un modèle qui consiste à séparer les tests en deux grands pans :
- Tests de comportements
- Tests d’intégration
Tests de comportements vs. tests d’intégration
Tests de comportements : Un test de comportement vérifie que le système retourne la bonne réponse. Ce test sera fragile si le calcul de la réponse n’est pas complètement déterministe.
Tests d’intégration : Un test d’intégration vérifie que le système retourne une réponse. Ce test sera plus robuste qu’un test de comportements face à des réponses non déterministes.
Exemple simpliste d’une calculatrice :
1. Test de comportements : Vérifier que 5+3 donne 8
2. Test de comportements : Vérifier que 2×3 donne 6
3. Test d’intégration : Vérifier que 4+2×5 donne un résultat
Ce modèle permet de définir une première typologie de test en le conjuguant avec celui qui classe par périmètre de test :
L’intérêt de ce modèle est qu’il donne un bon canevas pour réfléchir à la couverture de code par les tests.
Ainsi l’utilisation des 5 types de test donnés dans l’exemple permet d’avoir une couverture satisfaisante en jouant sur les tests de comportements et d’intégration des différents niveaux de périmètre testé :
- Tester exhaustivement la combinatoire des comportements avec les tests unitaires
- Tester exhaustivement l’intégration interne au composant avec les tests d’assemblage
- Tester les scenarios les plus critiques (nominaux, cas d’erreurs classiques) avec les tests fonctionnels
- Tester simplement l’intégration du composant avec les autres composants avec les tests d’intégration
- Si la nouvelle fonctionnalité n’est pas déjà couverte par les tests E2E existants et qu’elle est considérée suffisamment critique, alors ajouter un nouveau test de bout en bout, on s’intégrer dans un déjà existant
Ce découpage respecte la structure de pyramide qui favorise l’écriture de tests peu coûteux tout en ne négligeant pas l’écriture des tests dans un environnement plus proche de la production.
L’utilisation des tests d’intégration en complément des tests de comportements permet d’optimiser à la fois la couverture et l’effort de test :
- On teste exhaustivement la combinatoire avec des tests de comportement sur un périmètre le plus petit possible
- Les tests d’intégration permettent d’écrire des tests dans des environnements plus complets tout en étant robustes car ils ne vérifient pas le détail des données
Outil de rédaction : qui doit pouvoir comprendre le test ?
Lorsqu’un test de non-régression échoue, cela n’indique pas toujours une régression. Cela peut aussi indiquer un impact non anticipé, provoqué par un changement ailleurs sur le produit. (lien à la fin de l’article)
Comment déterminer s’il s’agit d’une régression ou d’un impact non anticipé ?
Si le test concerne une exigence technique, un développeur sera certainement la bonne personne pour répondre à cette question.
Si par contre le test concerne une exigence métier, ce sera plutôt un expert métier qui aura la réponse à la question.
Or, pour pouvoir donner une réponse, encore faut-il comprendre la question. Il faut pouvoir comprendre le test qui échoue pour pouvoir dire s’il s’agit d’une régression ou d’un impact non anticipé.
S’il s’agit d’un test technique, qui concerne une exigence technique, l’utilisation de code est idéale pour exprimer le test. Le développeur comprend le code, et l’utilisation directe de code donne à la fois un maximum de flexibilité et de meilleures performances d’exécution.
Si par contre il s’agit d’un test métier, qui concerne une exigence métier, on voudra alors utiliser un langage pseudo-naturel pour pouvoir exprimer le test sous une forme qui permettra d’impliquer les experts métier. On parle de rédiger des spécifications exécutables. (lien à la fin de l’article) Dans ce cas de figure, des outils spécifiques imposent un surcout supplémentaire à la création et à l’exécution mais celui-ci est largement compensé par l’intérêt d’impliquer directement les experts métier.
Combinaison avec le périmètre des tests
Selon ce modèle, on voit que les tests définis sous forme de spécifications exécutables ne sont pas nécessairement des tests système, qui se placent au niveau d’un utilisateur, ou qui manipulent l’interface graphique.
On conçoit très bien que des règles métier complexes puissent être implantées au niveau le plus bas du code. Dans cette logique, on voudrait rédiger des tests pour ces règles métier, sous forme de spécifications exécutables en impliquant fortement les experts métier. En pratique, la mise en place de ces tests ressemblerait fortement à l’implantation de tests unitaires.
Pour aller plus loin
La pyramide de test de Mike Cohn
How Google Tests Software
Les ingénieurs de Google (la couverture du livre cite James A. Whittaker, Jason Arbon and Jeff Carollo en tant que contributeurs principaux mais le livre est en réalité le travail de nombreux ingénieurs de Google) décrivent dans “How Google Tests Software” comment Google a radicalement changé la manière dont ils travaillent afin de s’assurer de la qualité à tous les niveaux avec un effort minimal de maintenance manuelle. Ils révèlent comment travaille Google de manière totalement transparente et directe, aussi la lecture de ce livre vous donnera un maximum d’information en un minimum de temps de lecture. Même si votre organisation n’a aucun espoir de devenir du calibre de Google (combien d’entreprises pourraient nourrir cette vision ?) vous pouvez toujours sélectionner et ré-utiliser de nombreuses idées ici et là. Au grand minimum, ce livre vous fera réfléchir et remettre en question votre manière de travailler, tout en vous suggérant des idées à essayer.
Introduction à l’intégration continue
Qu’est-ce qui se cache derrière un test qui échoue ?
Rédaction des spécifications exécutables
Que pensez-vous de cet article?
J’apprécierais vraiment si vous pouviez me laisser un commentaire pour me dire ce que vous appréciez ou ce qui pourrait être amélioré dans cet article.
Et si vous avez aimé cet article, merci d’applaudir 👏 et de le partager !
À bientôt 😊