Le tags, la fonctionnalité oubliée des lanceurs de tests
Il y a une fonctionnalité des lanceurs de tests que l’on utilise bien trop peu, moi le premier : les tags.
Avec un peu d’imagination ils peuvent pourtant nous rendre de chouettes services, et voir même changer certaines discussions autour des tests et de leur organisation.
C’est quoi les tags ?
Habituellement pour créer des groupes de tests, on se base sur la position du test au milieu de notre ensemble de tests. Les tests sont groupés car ils appartiennent à la même class de tests, à la même méthode describe
, au même fichier, à une même hiérarchie de fichiers.
Les tags sont un autre moyen de créer des groupes de tests sans avoir besoin de savoir où ils sont rangés. Certains outils parlent d’ailleurs de groupes plutôt que de tags.
Généralement, les tags se mettent en place via le mécanisme d’annotations du langage dans lequel sont écrits les tests.
Une fois les tags mis en place, on a un nouveau moyen de décider quels tests on souhaite lancer ou non. Nous verrons des exemples d’usages dans la suite de l’article.
Mon lanceur de tests ne gère pas les tags
C’est pas de bol...
Mais il y a de fortes chances que la communauté propose un plug-in qui permet d’avoir un mécanisme similaire[1].
Si ce n’est pas le cas tout n’est pas perdu. Il y a de grandes chances que le lanceur de tests permette de filtrer les tests en fonction de leur nom[2]. On peut alors décider d’inclure les tags à la fin du nom des tests et filtrer sur le pattern qui nous intéresse. Ajouter un tag dans le nom du test rajoute du bruit, de l’information qui n’est pas pertinente dans certains cas, et il est important d’avoir une convention qui permet de facilement savoir si une information est un tag ou non. Commencer l’ensemble des tags par un croisillon (#) est sans doute une bonne idée.
Examples d’usage
Voyons quelques idées de ce que nous permettent de faire les tags.
Type de test
La première idée est la plus évidente, si évidente qu’elle peut sembler inutile, et pourtant...
Les tags peuvent permettre d’indiquer le type du test. S’agit-il d’un test unitaire, d’un test d’intégration, d’un test end-2-end, d’un test d’acceptance, ou d’un autre type de test ?
Avec les tags, on peut alors décider de ne lancer que certains types de tests à certains moments.
Cette idée semble inutile puisqu’il y a des chances que vous vous serviez déjà de test suites rangées dans des dossiers différents pour séparer les types de tests, et qu’il vous est déjà possible de décider quels types de test exécuter.
L’inconvénient du tri des types de tests par dossier est qu’elle nous force à maintenir synchronisé une ou plusieurs hiérarchies de fichiers miroirs de celle du code de production. Et avouons-le franchement, la plupart du temps cette synchronisation n’est pas faite. On a alors des hiérarchies de dossiers complètement différentes de tous les côtés.
Grâce aux tags, on peut abandonner cette contrainte et placer tous les tests dans une même hiérarchie, ce qui nous facilite grandement la maintenabilité.
On peut même envisager d’aller plus loin et de mettre les tests directement à côté du code et quand même avoir un moyen de choisir quels types de tests on veut lancer.
Et là, plus de hiérarchies de dossier à maintenir synchronisées et pourtant il est possible de sélectionner facilement quels types de test on souhaite lancer.
Dépendances
La seconde idée est une continuation de la précédente.
Mais d’abord permettez-moi de vous poser quelques questions :
Combien de fois avez-vous eu un débat pour décider si un test est un test unitaire ? Ou plutôt un test d’intégration ? Ou un alors test d’acceptance ? Peut-être plutôt un test end-2-end ?
Combien de temps avez-vous perdu à vous écharper en équipe pour savoir comment classer un test et dans quel dossier le ranger ?
Et si le plus important ce n’est pas le type du test mais ses caractéristiques ?
Pensez-y 2 minutes : pourquoi tient-on tant à connaitre le type d’un test ?
Est-ce que pouvoir séparer les tests trop lents des autres n’y est pas pour beaucoup ?
Si votre manière de travailler s’appuie beaucoup sur les tests, par exemple si vous pratiquez le TDD, vous n’avez surement pas envie d’attendre un long moment avant de savoir si vos modifications ont eu un impact imprévu sur le système. Il y a des chances que vous lanciez fréquemment les tests les plus rapides, comme un premier filet de sécurité, et de temps à autre l’ensemble de tous les tests, même les plus lents, pour avoir un filet de sécurité plus complet.
Alors plutôt que de débattre sur le type des tests demandons-nous pourquoi ils sont lents. Généralement les tests sont lents dès lors que l’on fait des entrées/sorties. Les tests qui touchent à une base de données, à un système de fichier, qui font des appels à des services externes via le réseau sont bien plus lents que les autres tests[3].
On tient alors notre nouvelle idée de catégorie de tags: des tags qui indiquent les dépendances.
Lorsqu’un test va avoir besoin d’une dépendance particulière on peut l’indiquer avec un tag, comme database
, external-call
, network
, filesystem
, ...
Avec ce type de tags on est plus obligé d’essayer de catégoriser les tests précisément, on a simplement à décrire les dépendances dont ils ont besoin, ce qui va nous éviter des débats sans fin.
On peut désormais sélectionner ou exclure certains tests en fonction de ce dont ils dépendent. Lorsque l’on a besoin de ne lancer que les tests les plus rapides il est facile d’exclure les dépendances pénibles.
En bonus, s’il manque une dépendance dans un environnement, par exemple si l’on n’a pas moyen de faire des appels à des services externes parce qu’on est dans le train, on peut facilement exclure tous les tests qui ne passeront de toute façon pas.
Cette idée de sélection par dépendance, qui est ingérable avec le système de fichier, devient possible avec les tags.
Documentation plus précise
Je parle souvent d’utiliser les tests comme documentation, pour les devs, mais aussi pour le reste de l’équipe, voir même pour le "métier".
En PHP, avec PHPUnit, l’option '--testdox' permet de générer de la documentation en texte ou sous forme d’un fichier HTML, sauf que...
Différentes personnes sont intéressées par différents aspects du système. Plutôt que de générer des documents énormes que personne ne va lire il est possible d’ajouter des tags pour chaque sujet d’intérêt.
Avec ces tags on peut maintenant générer une documentation spécifique pour chacun :
- une documentation qui parle des fonctionnalités de paiements en filtrant sur le tag
feat-payment
- une documentation sur le fonctionnement du backoffice avec
tool-bo
- ...
Là encore on peut s’en sortir avec le système de fichier mais il existe aussi des sujets plus transverses, tels que la sécurité (security
), la traduction (i18n
), ou les règles métiers qui ne concernent que les clients de certains pays (market-es
)...
En se servant des tags on peut mettre des marqueurs sur les sujets qui nous intéressent de manière récurrente.
Lien avec le système de tickets
Les tags peuvent également permettre de faire le lien entre un système de gestion de tickets.
Tu en as marre de tes tests ?
J’ai créé une formation vidéo qui aide les développeuses et développeurs à améliorer leurs tests automatisés.
Dans cette formation je partage les idées et techniques qui permettent de rendre des tests lents, qui cassent à chaque modification du code et sont incompréhensibles en des tests avec lesquels on a plaisir à travailler.
Avec le numéro du ticket en tant que tag on peut facilement retrouver un test de non-régression pour un bug bug-3457
ou trouver tous les tests liés à une user story US-89
.
Je ne pense pas que ces tags soient très utiles sur le long terme puisqu’après un certain temps savoir qu’un comportement a été créé en lien avec un ticket n’est plus une information très pertinente selon moi, mais ils peuvent toutefois servir à court terme.
Par exemple, l’outil de build pourrait générer une documentation spécifique basée sur les tests pour chaque user story et l’afficher directement dans un commentaire de pull request[4] ou vérifier qu’un test de non-régression a bien été posé avant de résoudre le bug.
Nomenclature
Comme pour tout outil, en abuser peut avoir de désagréables conséquences.
Pour éviter que l’utilisation des tags ne devienne un immense foutoir il est important de réfléchir à une nomenclature. Pour cela il faut se demander ce que vous pouvez tirer de l’utilisation des tags, que ce soit pour sélectionner les tests à lancer ou pour extraire de l’information à partir de ceux-ci.
Une fois que vous avez défini ce à quoi vont vous servir les tags et identifié des catégories vous pouvez utiliser des préfixes pour facilement identifier les tags.
On a croisé quelques idées dans cet article :
feat-payment
US-89
bug-3457
tool-backoffice
market-es
domain-delivery
Pensez également à faire du nettoyage de temps à autre et à supprimer les tags qui ne vous servent plus - particulièrement si vous utilisez les tags liés au système de gestion de tickets.
Pour cela, laissez-vous aider par votre lanceur de test. S’il permet de filtrer les tests par groupe il a certainement une commande permettant de lister les tags. Par exemple, PHPUnit a une commande --list-groups
. Si le lanceur de test ne vous aide pas vous pourrez probablement vous en sortir à coup de grep
.
Certains tags auront des durées de vie plus ou moins longues de par leur nature, vos usages changeront sans doute également, et c’est très bien.
J’espère que cet article vous a donné des idées, celles présentées ou d’autres, sur la manière dont vous pouvez incorporer l’usage des tags à votre quotidien pour tirer le meilleur parti de vos tests.
Et si vous voulez faire en sorte d'avoir des tests avec lesquels vous prendrez un réel plaisir à travailler, vous pouvez accéder à ma formation vidéo sur l'amélioration des tests automatisés. Il vous est aussi possible de prendre un rendez-vous pour que nous travaillions ensemble à faire passer votre équipe au niveau supérieur.
Par exemple, jest-runner-groups si vous utilisez Jest. ↩︎
L’option testnamepatternregex de Jest peut aider. ↩︎
Oserais-je simplement dire que ces tests sont bien plus lents que les tests unitaires ? ↩︎
Si votre workflow utilise des PRs, bien sûr. ↩︎