Ce que la couverture de code vous révèle vraiment
Votre suite de tests passe. Votre rapport de couverture affiche 85 %. Le tableau de bord est au vert. Mais ce chiffre signifie-t-il réellement que votre code fonctionne correctement ?
La couverture de code est l’une des métriques les plus visibles dans les tests frontend, pourtant elle est fréquemment mal comprise. Cet article explique ce que les métriques de couverture mesurent réellement, pourquoi des pourcentages élevés peuvent masquer des lacunes sérieuses, et comment interpréter ces chiffres dans de vrais projets JavaScript.
Points clés à retenir
- La couverture de code mesure quelles lignes ont été exécutées pendant les tests, pas si le code se comporte correctement
- La couverture de branches révèle des lacunes que la couverture de lignes manque, en particulier dans la logique conditionnelle
- Des pourcentages de couverture élevés peuvent créer une fausse confiance lorsque les tests manquent d’assertions significatives
- Différents fournisseurs de couverture (Istanbul vs V8) peuvent rapporter des chiffres différents pour un code identique
- Utilisez la couverture comme un outil de diagnostic pour trouver les angles morts, pas comme un score de qualité
Ce que la couverture de code mesure réellement
La couverture de code vous indique une chose : quelles parties de votre code source ont été exécutées pendant vos tests. C’est tout.
Elle ne vous dit pas si le code s’est comporté correctement. Elle ne confirme pas que vos assertions ont détecté des bugs. Elle ne vérifie pas que les cas limites ont été gérés. Les outils de couverture instrumentent simplement votre code et suivent ce qui a été exécuté.
Lorsque vous exécutez jest --coverage ou activez la couverture dans Vitest, l’outil surveille l’exécution et rapporte des pourcentages. Ces pourcentages représentent l’exécution, pas la justesse.
Comprendre les métriques de couverture de tests
La plupart des outils de couverture de tests JavaScript rapportent plusieurs métriques distinctes. Chacune mesure quelque chose de différent.
La couverture de lignes (line coverage) suit si chaque ligne de code source a été exécutée. La couverture d’instructions (statement coverage) compte les instructions exécutées — ce qui diffère des lignes lorsque plusieurs instructions apparaissent sur une seule ligne. La couverture de fonctions (function coverage) rapporte si chaque fonction a été appelée au moins une fois.
La couverture de branches (branch coverage) va plus loin. Elle suit si chaque chemin à travers la logique conditionnelle a été exécuté. Un bloc if/else a deux branches. La couverture de branches exige que les deux chemins soient exécutés.
C’est là que la distinction compte :
function getDiscount(user) {
if (user.isPremium || user.hasPromo) {
return 0.2
}
return 0
}
Un test avec user.isPremium = true atteint 100 % de couverture de lignes. Chaque ligne s’exécute. Mais la couverture de branches révèle la lacune : vous n’avez jamais testé quand isPremium est false mais hasPromo est true, ou quand les deux sont false.
C’est pourquoi la distinction entre couverture de branches et couverture de lignes est importante. La couverture de lignes peut atteindre 100 % tout en laissant des chemins logiques complètement non testés.
Pourquoi une couverture élevée peut être trompeuse
Un test qui exécute du code sans assertions significatives gonfle la couverture sans détecter de bugs. Considérez :
test('processes order', () => {
processOrder(mockOrder)
// No assertions
})
Ce test pourrait exécuter des dizaines de lignes, augmentant votre pourcentage de couverture. Mais il ne vérifie rien. Le code pourrait retourner de mauvaises valeurs, lever des erreurs silencieusement interceptées, ou corrompre l’état — et ce test passerait quand même.
Les outils de couverture ne peuvent pas faire la distinction entre un test qui valide minutieusement le comportement et un qui exécute simplement du code. Les deux comptent de la même manière dans votre pourcentage.
Discover how at OpenReplay.com.
Fournisseurs de couverture : pourquoi les chiffres varient
La couverture de tests JavaScript moderne repose sur différentes approches d’instrumentation. Jest utilise par défaut l’instrumentation de type Istanbul, qui transforme votre code avant l’exécution. Vitest prend en charge à la fois Istanbul et la couverture native basée sur V8.
Ces fournisseurs peuvent rapporter des chiffres différents pour un code et des tests identiques. La couverture V8 opère au niveau du moteur et compte parfois la couverture différemment de l’approche de transformation de source d’Istanbul.
Changer de fournisseur, mettre à niveau des outils ou modifier la configuration peut faire varier votre couverture rapportée sans aucun changement de code. Cela ne signifie pas qu’une approche est fausse — elles mesurent des choses légèrement différentes à différents niveaux.
Traitez les chiffres de couverture comme des signaux directionnels, pas comme des mesures précises.
Où la couverture aide et où elle induit en erreur
La couverture est utile pour :
- Identifier les fichiers ou fonctions complètement non testés
- Repérer le code mort qui ne s’exécute jamais
- Trouver les branches que vous avez oublié de tester
- Suivre les tendances au fil du temps (baisse de couverture sur du nouveau code)
La couverture induit en erreur quand :
- Les équipes poursuivent des pourcentages au lieu de tester le comportement
- Les tests exécutent du code sans affirmer les résultats
- Des chiffres élevés créent une fausse confiance dans la qualité des tests
- Les seuils poussent les développeurs à écrire des tests superficiels
Interpréter la couverture dans de vrais projets
Utilisez les rapports de couverture comme un outil de diagnostic, pas comme un score de qualité. Lorsque vous voyez des lignes non couvertes, demandez-vous : ce chemin de code est-il important ? S’il gère des erreurs, des cas limites ou une logique critique, écrivez des tests pour lui. S’il est véritablement inaccessible ou trivial, demandez-vous si le code devrait exister du tout.
Examinez la couverture en parallèle de vos tests, pas à leur place. Un fichier avec 60 % de couverture et des assertions solides offre souvent plus de confiance qu’un fichier avec 95 % de couverture et des tests faibles.
Dans les revues de code, les différences de couverture aident à identifier si le nouveau code inclut des tests. Mais la revue elle-même devrait évaluer si ces tests vérifient un comportement significatif.
Faire fonctionner la couverture pour votre équipe
Définissez les seuils de couverture de manière réfléchie. Un plancher de 70-80 % prévient les lacunes évidentes sans pousser les équipes vers du théâtre de couverture. Plus important encore, concentrez-vous sur la couverture de branches pour le code riche en logique — elle détecte des lacunes que la couverture de lignes manque.
Exécutez la couverture en CI pour suivre les tendances, mais ne faites pas échouer les builds sur de petites baisses. Le refactoring réduit souvent temporairement la couverture lorsque du code testé est supprimé ou restructuré.
Conclusion
L’objectif n’est pas un chiffre. C’est la confiance que vos tests détectent de vrais bugs avant que les utilisateurs ne les rencontrent. La couverture vous aide à trouver les angles morts. Une bonne conception de tests, des assertions significatives et des revues réfléchies déterminent si vous les comblez réellement.
FAQ
La plupart des équipes visent 70-80 % comme plancher raisonnable. Cependant, le pourcentage compte moins que ce que vous testez. Concentrez-vous sur la couverture des chemins critiques, la gestion des erreurs et la logique métier. Un pourcentage plus faible avec des assertions solides bat souvent une couverture élevée avec des tests superficiels qui manquent de vérification significative.
Évitez de faire échouer les builds sur de petites baisses de couverture. Le refactoring réduit souvent temporairement la couverture lorsque du code testé est supprimé ou restructuré. À la place, utilisez les tendances de couverture pour identifier les patterns et examinez les différences de couverture dans les pull requests pour vous assurer que le nouveau code inclut des tests appropriés.
Différents fournisseurs de couverture utilisent différentes approches d'instrumentation. Istanbul transforme le code avant l'exécution tandis que V8 opère au niveau du moteur. Ces approches mesurent des choses légèrement différentes, donc changer de fournisseur ou mettre à niveau des outils peut faire varier les chiffres rapportés sans aucun changement réel de code.
Examinez vos assertions, pas seulement vos chiffres de couverture. Les tests sans assertions ou avec seulement des vérifications triviales gonflent la couverture sans détecter de bugs. Les outils de tests de mutation peuvent aider en introduisant de petits changements de code pour vérifier que vos tests échouent réellement quand le comportement change de manière inattendue.
Gain control over your UX
See how users are using your site as if you were sitting next to them, learn and iterate faster with OpenReplay. — the open-source session replay tool for developers. Self-host it in minutes, and have complete control over your customer data. Check our GitHub repo and join the thousands of developers in our community.