Vos tests sont-ils une illusion de sécurité ?
Imaginez : vous avez 95 % de couverture de code, tous les tests sont verts, le CI/CD passe. Vous êtes sûr que votre code PHP est protégé contre les régressions. Mais l'est-il vraiment ?
J'ai moi-même longtemps vécu dans cette illusion, jusqu'à ce que je sois confronté à une situation : le test passait, alors que j'avais accidentellement remplacé && par || dans une condition critique. Le test ne vérifiait tout simplement pas cette branche. La couverture était de 100 %, mais la logique, non.
Faites connaissance avec le test de mutation (mutation testing) — une méthode qui « tue » impitoyablement vos tests pour déterminer à quel point ils sont réellement fiables. Dans cet article, nous verrons comment l'appliquer en PHP en utilisant le puissant outil Infection, et pourquoi cela change la donne.
Qu'est-ce que le test de mutation et pourquoi en a-t-on besoin ?
Le test de mutation est une approche dans laquelle de petites modifications intentionnelles (mutations) sont apportées à votre code source. Par exemple, l'opérateur + est remplacé par -, true par false, ou une ligne entière est supprimée. Après chaque mutation, vos tests sont exécutés.
Si le test échoue — la mutation est « tuée », ce qui signifie que le test vérifie réellement ce morceau de code. Si le test réussit — la mutation « survit ». C'est un signal d'alarme : soit le test ne vérifie pas cette condition, soit il est mal écrit.
Contrairement à la métrique de « couverture de code » (code coverage), qui indique seulement quelles lignes ont été exécutées, le test de mutation vérifie la qualité des vérifications. Un pourcentage élevé de couverture n'est pas une garantie, tandis que le score de mutation (Mutation Score Indicator, MSI) est un indicateur réel de fiabilité.
Pourquoi est-ce important pour un développeur PHP ?
- Détection des tests « morts » — ceux qui sont toujours verts mais ne vérifient rien.
- Identification des lacunes dans la logique — par exemple, des conditions limites manquées.
- Confiance accrue lors du refactoring — vous savez exactement quels tests protègent le code.
- Gain de temps — au lieu d'un audit manuel des tests, vous obtenez un rapport automatique.
Outils pour le test de mutation en PHP
Le leader sur la scène PHP est Infection (anciennement connu sous le nom de Humbug). Il s'intègre facilement avec PHPUnit et Pest, prend en charge de nombreuses mutations et fournit des rapports visuels.
Autres options : Humbug (le prédécesseur, mais moins actif) et Mutagen (expérimental). Nous nous concentrerons sur Infection — c'est la norme moderne.
Pratique : configurer Infection dans un projet
Installons Infection et exécutons-le sur un exemple réel. Supposons que nous ayons une classe simple pour calculer une remise :
<?php// src/DiscountCalculator.phpclass DiscountCalculator{ public function calculate(float $price, bool $isPremium): float { if ($isPremium) { return $price * 0.9; // remise de 10% }
return $price; }}Et son test :
<?php// tests/DiscountCalculatorTest.phpuse PHPUnit\\Framework\\TestCase;
class DiscountCalculatorTest extends TestCase{ public function testPremiumDiscount(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(100.0, true); $this->assertEquals(90.0, $result); }
public function testRegularPrice(): void { $calculator = new DiscountCalculator(); $result = $calculator->calculate(100.0, false); $this->assertEquals(100.0, $result); }}Couverture — 100 %. Mais vérifions avec des mutations.
Installation et exécution d'Infection
composer require --dev infection/infection./vendor/bin/infectionAprès