# Quel score de mutation viser avec Infection avant de le rendre bloquant

> Un score de mutation calculé mais jamais consulté ne sert à rien. Comment fixer un seuil réaliste avec Infection, puis le rendre bloquant en CI sans décourager l'équipe.

- Auteur : Clément Hadrot
- Publié le : 2025-08-18
- Mis à jour le : 2025-08-18
- Catégorie : Tests
- URL : https://wpmoderne.dev.wordpress-developpement.fr/tests/score-mutation-infection-avant-bloquant/

## L’essentiel

- Mesurer le score existant avant de fixer un seuil, jamais l'inverse
- Rendre le seuil bloquant progressivement, module par module
- Distinguer un mutant tué et un mutant simplement ignoré

« MSI: 61% » : c'est la ligne que produisait Infection à chaque exécution manuelle, sans qu'aucune décision n'en découle depuis son installation huit mois plus tôt dans une extension de gestion d'abonnements. L'outil tournait, le chiffre s'affichait, et rien ne se passait ensuite : ni seuil fixé, ni intégration à la pipeline, ni discussion en équipe sur ce que ce nombre signifiait vraiment.

Un score de mutation mesure la capacité d'une suite de tests à détecter des modifications volontaires introduites dans le code, appelées mutants : un opérateur de comparaison inversé, une condition supprimée, une valeur de retour modifiée. Un score élevé indique que la suite réagit à ces altérations ; un score faible révèle des tests qui passent quel que soit le comportement réel du code, ce qui les rend décoratifs plutôt que protecteurs.

## Pourquoi un score mesuré sans seuil ne sert à rien

Un chiffre affiché sans conséquence devient rapidement un chiffre ignoré. Sans seuil fixé, aucune régression du score ne déclenche d'alerte, et rien n'empêche le score de continuer à baisser silencieusement à mesure que du code nouveau s'ajoute sans tests suffisamment précis. La mesure seule, sans mécanisme de contrôle, ne change aucun comportement.

## Fixer un seuil réaliste à partir du score mesuré, pas d'un chiffre théorique

Viser d'emblée un score de quatre-vingt-dix pour cent sur une base de code où le score mesuré est de soixante et un pour cent condamne le seuil à être perçu comme inatteignable, et pousse souvent à le contourner plutôt qu'à l'atteindre honnêtement. La méthode retenue fixe le seuil initial légèrement en dessous du score mesuré, pour ne bloquer que les régressions futures sans exiger de rattrapage immédiat sur l'existant :

```
{
    "source": {
        "directories": ["inc"]
    },
    "minMsi": 58,
    "minCoveredMsi": 75,
    "logs": {
        "text": "infection.log"
    }
}
```

Le paramètre `minMsi` porte sur l'ensemble du code source, y compris les portions non couvertes par des tests. Le paramètre `minCoveredMsi` porte uniquement sur le code déjà couvert, et constitue souvent le levier le plus pertinent à court terme : il pousse à améliorer la qualité des tests existants avant même d'en écrire de nouveaux.

### Rendre le seuil bloquant progressivement, module par module

Plutôt que d'appliquer le seuil à l'ensemble du projet d'un coup, ce qui bloquerait immédiatement toute contribution touchant une zone historiquement mal testée, le seuil s'active module par module, en commençant par les zones critiques pour l'activité :

- Module de facturation : seuil bloquant activé immédiatement, score déjà satisfaisant.
- Module de gestion des abonnements : seuil bloquant activé après un mois de stabilisation.
- Module d'export de rapports, peu critique : seuil mesuré mais non bloquant pour l'instant.

> L'essentiel à retenir : Mesurer le score existant avant de fixer un seuil, jamais l'inverse ; Rendre le seuil bloquant progressivement, module par module ; Distinguer un mutant tué et un mutant simplement ignoré

## Distinguer un mutant tué et un mutant ignoré

Infection classe certains mutants comme « ignorés » lorsqu'ils touchent du code jugé équivalent quel que soit le résultat, par exemple une modification qui n'affecte que la performance sans changer le comportement observable. Confondre un score élevé grâce à de nombreux mutants ignorés avec un score élevé grâce à des tests réellement efficaces conduit à une fausse confiance. Le rapport détaillé, généré avec l'option `--only-covered`, distingue précisément ces catégories :

```
vendor/bin/infection --only-covered --min-msi=58 --threads=4
```

| Résultat du mutant | Signification | Action |
| --- | --- | --- |
| Tué | Un test a détecté la modification | Aucune, c'est l'objectif |
| Survivant | Aucun test n'a réagi au changement | Ajouter ou renforcer une assertion |
| Ignoré | Jugé sans impact observable | Vérifier que c'est réellement le cas |

## Réagir concrètement à un mutant survivant

Un mutant survivant pointe précisément la ligne modifiée sans effet sur les tests, ce qui rend le correctif direct : si un mutant remplace `$total >= $seuil` par `$total > $seuil` sans faire échouer aucun test, un cas limite testant exactement l'égalité au seuil manque à la suite, et son ajout suffit à faire remonter le score sur ce point précis.

> Un score de mutation ne remplace jamais la couverture de code, il la complète en posant une question différente : la ligne exécutée par un test l'est-elle vraiment vérifiée, ou seulement traversée sans conséquence sur l'assertion ?

## En résumé

Un score de mutation n'a de valeur que rendu bloquant, mais un seuil fixé sans tenir compte du score réel existant décourage plus qu'il ne protège. Partir du score mesuré, l'activer progressivement module par module, et distinguer soigneusement mutants tués, survivants et ignorés : cette méthode transforme Infection d'un outil décoratif en un véritable garde-fou de qualité.
