Le WordPress d'aujourd'hui, décodé pour les développeurs

Tests

Mythe : une couverture de code à 100 % élimine les bugs, ce qu’elle garantit

Viser 100 % de couverture comme objectif en soi masque une confusion fréquente entre lignes exécutées et comportements réellement vérifiés. Ce que ce chiffre prouve, et ce qu'il ne prouve pas.

Par Clément Hadrot • 6 janvier 2026 • 4 min de lecture • Aucun commentaire
Mythe : une couverture de code à 100 % élimine les bugs, ce qu'elle garantit

« Notre module de facturation affiche 100 % de couverture de code » : cette phrase, entendue lors d’une revue de projet pour une plateforme de billetterie associative, sonnait comme une garantie de fiabilité. Trois semaines plus tard, un bug de calcul de TVA sur les billets à tarif réduit passait pourtant inaperçu jusqu’à la production, alors que la ligne concernée s’exécutait bien à chaque test de la suite.

Ce paradoxe apparent n’en est pas un pour qui comprend ce que mesure réellement un outil de couverture comme PCOV ou Xdebug : le pourcentage de lignes exécutées pendant l’exécution de la suite de tests, rien de plus. Une ligne peut s’exécuter des centaines de fois sans qu’aucune assertion ne vérifie correctement son résultat.

Ce que la couverture mesure réellement

Un outil de couverture instrumente le code exécuté et note, ligne par ligne, si elle a été atteinte au moins une fois pendant la suite de tests. Il ne sait rien du contenu des assertions qui suivent cette exécution, ni de leur pertinence par rapport au comportement attendu. Une ligne peut être couverte à 100 % et pourtant jamais réellement vérifiée.

Le cas du bug de calcul de TVA

L'essentiel à retenir : 100 % de couverture signifie que chaque ligne s'est exécutée, pas qu'elle a été vérifiée correctement ; Une assertion absente ou trop permissive laisse une ligne couverte sans être réellement testée ; La couverture reste un indicateur de périmètre, jamais une preuve de correction

La fonction incriminée calculait le montant de TVA applicable à un billet, avec un taux réduit pour les tarifs solidaires. Le test existant appelait bien la fonction avec un tarif solidaire, exécutant donc la branche concernée, mais son assertion se limitait à vérifier que le résultat était un nombre positif, sans vérifier sa valeur exacte :

// Test insuffisant, malgré 100 % de couverture de la fonction
public function ilCalculeUneTvaPourLesTarifsSolidaires(): void
{
    $tva = wpm_calculer_tva_billet(15.00, 'solidaire');

    $this->assertGreaterThan(0, $tva); // vrai même si le taux est incorrect
}

// Version corrigée, qui vérifie la valeur exacte attendue
public function ilCalculeUneTvaDe55PourcentPourLesTarifsSolidaires(): void
{
    $tva = wpm_calculer_tva_billet(15.00, 'solidaire');

    $this->assertEqualsWithDelta(0.82, $tva, 0.01);
}

Les deux tests couvrent exactement la même ligne de code. Seul le second aurait détecté le bug, qui appliquait par erreur le taux normal de 20 % au lieu du taux réduit attendu pour ce tarif.

Le mutation testing, un révélateur complémentaire

Cette catégorie de faille se détecte typiquement par le mutation testing, qui modifie volontairement le code source pour vérifier que les tests existants échouent bien face à un changement de comportement. Ce sujet dépasse le cadre de cet article, déjà traité ailleurs en détail, mais il complète naturellement la lecture d’un taux de couverture brut.

Ce que 100 % de couverture prouve réellement

  • Chaque ligne du code source s’est exécutée au moins une fois pendant la suite de tests, ce qui exclut le code totalement mort ou jamais atteint.
  • Aucune branche conditionnelle n’a été laissée totalement sans exécution, ce qui reste une information utile pour repérer du code oublié.
  • La suite de tests couvre l’intégralité du périmètre déclaré, ce qui facilite une revue exhaustive fichier par fichier.

Ce que 100 % de couverture ne prouve pas

  • Que chaque assertion vérifie la bonne valeur, et non une simple propriété générique comme la non-nullité ou la positivité d’un résultat.
  • Que les cas limites et les combinaisons d’entrées rares ont été envisagés, au-delà du chemin d’exécution le plus évident.
  • Que le comportement testé correspond réellement à l’attente métier, et non à une interprétation erronée partagée par le code et son test.

Un pourcentage de couverture répond à la question « qu’est-ce qui s’est exécuté ? », jamais à la question « qu’est-ce qui a été vérifié correctement ? ».

En résumé

Une couverture de code à 100 % constitue un repère utile de périmètre testé, jamais une preuve d’absence de bug. Le cas du calcul de TVA sur cette plateforme de billetterie associative l’illustre directement : la ligne fautive s’exécutait à chaque test, mais l’assertion trop permissive laissait passer un taux erroné sans jamais le signaler, malgré un pourcentage affiché à son maximum.

Partager :

À propos de l'auteur

Clément Hadrot

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi