Un rapport annonce quatre-vingt-douze pour cent. L'équipe respire. La semaine suivante, un bug part en production dans une fonction que le rapport comptait comme couverte.
Le chiffre n'avait pas menti. Il ne disait simplement pas ce que tout le monde avait cru lire.
Définition
La couverture de code mesure la proportion du code source réellement exécutée pendant l'exécution des tests. L'outil instrumente le programme, note ce qui a été traversé, et rend un rapport ligne par ligne. Il mesure un passage, jamais une vérification.
export function remise(total, code) {
if (code === "BIENVENUE") {
return total * 0.9;
}
if (total > 100) {
return total - 10;
}
return total;
}Un unique test qui appelle remise(50) traverse les deux conditions et le dernier return. La fonction est comptée comme exécutée, trois instructions sur cinq le sont, mais aucune des deux réductions n'a jamais été calculée.
Quatre mesures, pas une
| Mesure | Ce qu'elle compte |
|---|---|
| Lignes | Les lignes du fichier qui ont été atteintes |
| Instructions | Les instructions exécutées, plusieurs par ligne parfois |
| Branches | Chaque issue d'un if, d'un switch ou d'un Opérateur ternaire (?:) |
| Fonctions | Les fonctions appelées au moins une fois |
Sur l'exemple ci-dessus, la couverture des fonctions atteint cent pour cent tandis que celle des branches plafonne à la moitié. C'est la colonne des branches qui porte l'information utile, et c'est celle qu'on regarde en dernier.
Pourquoi viser cent pour cent se retourne
Un seuil trop haut change la nature des tests écrits. On finit par appeler des fonctions sans rien affirmer sur leur résultat, pour éclairer une ligne rouge dans le rapport. La suite grossit, le temps d'exécution grimpe, et la confiance ne bouge pas.
Une couverture haute ne prouve pas que le code est juste. Elle prouve qu'il a été exécuté. Un test sans expect couvre exactement autant de lignes qu'un test qui vérifie tout.
Questions fréquentes
Quel seuil est raisonnable ?
Entre soixante-dix et quatre-vingts pour cent sur les branches convient à la plupart des projets applicatifs, et un seuil plus élevé se justifie sur du code de calcul ou de facturation. L'usage le plus fécond n'est pas le seuil global mais la règle de non-régression : interdire que le chiffre baisse d'une version à l'autre.
Comment lire un rapport sans se tromper ?
En ouvrant le rapport HTML plutôt qu'en lisant le total. Les lignes non couvertes y apparaissent surlignées, et l'on découvre presque toujours que ce sont les cas d'erreur, les branches de secours et les gardes qui ne sont jamais empruntés. Ce sont pourtant eux qui cassent en production.
Quelle différence entre les deux moteurs de mesure ?
Celui du moteur V8 lit les compteurs déjà tenus par Node.js, il est rapide et ne modifie pas le code. Celui d'Istanbul réécrit le code pour y poser ses compteurs, il est plus lent mais reste plus précis sur les branches et sur la correspondance avec le fichier d'origine. Le premier convient au quotidien, le second aux rapports que l'on publie.