Les fichiers de couverture de code, ces petits artefacts XML qui font briller les yeux des devs en quête de métriques parfaites, et qui transforment les dashboards SonarQube en tableaux de bord dignes d’un cockpit d’Airbus. Aujourd’hui, on parle de deux formats stars de PHPUnit : coverage-clover.xml et coverage-cobertura.xml. Aucun des deux ne va vous faire gagner le prix Nobel de l’innovation, mais ils ont le mérite d’exister. Alors, à quoi servent-ils vraiment ? Et surtout, lequel utiliser ?
Clover et Cobertura : les dinosaures de la couverture de code
Commençons par le plus ancien, coverage-clover.xml. Ce format est le vénérable ancêtre des rapports de couverture que l’on retrouve encore partout dans les projets PHP. Il est généré par PHPUnit avec l’option --coverage-clover et produit un fichier XML qui détaille la couverture du code analysé. Son contenu n’est clairement pas destiné à être lu avec un café le dimanche matin, mais les outils d’analyse savent parfaitement quoi en faire.
Exemple de sortie (parce qu’il faut bien voir à quoi ressemble l’horreur) :
<?xml version="1.0" encoding="UTF-8"?>
<coverage generated="1712345678">
<project timestamp="1712345678">
<file name="/var/www/src/Calculator.php">
<metrics loc="42" ncloc="30" classes="1" methods="3"
coveredmethods="2" statements="10" coveredstatements="8" />
</file>
</project>
</coverage>
Passons maintenant à coverage-cobertura.xml. Ce format vient de l’écosystème Cobertura et est également proposé par PHPUnit avec l’option --coverage-cobertura. Sa structure est différente et expose notamment de manière très explicite les taux de couverture des lignes et des branches.
<?xml version="1.0"?>
<coverage line-rate="0.8" branch-rate="0.0"
lines-covered="8" lines-valid="10">
<packages>
<package name="src" line-rate="0.8">
<classes>
<class name="Calculator"
filename="src/Calculator.php"
line-rate="0.8">
</class>
</classes>
</package>
</packages>
</coverage>
Cobertura n’est donc pas une « nouvelle version » de Clover. Ce sont simplement deux formats différents destinés à transporter à peu près la même information vers d’autres outils.
SonarQube et ses caprices : lequel choisir ?
Et c’est ici que les choses deviennent intéressantes. Si votre objectif est d’envoyer la couverture d’un projet PHP ou Symfony vers SonarQube, inutile de collectionner les fichiers XML comme des Pokémon. Clover est le choix naturel.
Dans un projet Symfony, on peut par exemple produire le rapport avec PHPUnit :
php -d xdebug.mode=coverage bin/phpunit --coverage-clover=coverage-clover.xml
Puis indiquer simplement à SonarQube où le trouver dans sonar-project.properties :
sonar.php.coverage.reportPaths=coverage-clover.xml
Et c’est tout. PHPUnit exécute les tests, Xdebug ou PCOV collecte la couverture, PHPUnit fabrique le fichier Clover et SonarQube vient ensuite le lire. Chacun fait son boulot et personne n’a besoin d’inventer un pipeline de 200 lignes.
Le XML est vieux, mais ce n’est pas vraiment le problème
On pourrait se moquer du XML et chercher quelque chose de plus moderne, mais ce serait surtout changer de problème. Ces fichiers ne sont pas destinés aux humains : ce sont des formats d’échange entre PHPUnit, la CI et les outils d’analyse. Qu’ils soient moches n’a donc finalement aucune importance.
Leur principale limite est ailleurs : un rapport de couverture dit seulement quelles lignes ont été exécutées pendant les tests. Il ne dit absolument pas si vos tests sont bons.
- Une ligne couverte peut être très mal testée.
- Un test peut exécuter une méthode sans vérifier correctement son résultat.
- 100 % de couverture n’empêche absolument pas les bugs.
- La couverture ne mesure ni la pertinence des assertions ni la qualité des cas testés.
C’est d’ailleurs pour cette raison que des outils comme Infection et les tests de mutation sont intéressants en complément : au lieu de demander simplement « est-ce que cette ligne a été exécutée ? », ils commencent à poser une question beaucoup plus méchante : « si je modifie volontairement ce code, est-ce que tes tests s’en rendent compte ? ».
Alors, Clover ou Cobertura ?
Pour un projet Symfony avec PHPUnit et SonarQube, la réponse est finalement assez simple : utilisez Clover. Cobertura reste parfaitement utile lorsque votre CI ou un autre outil le demande, mais il n’y a aucune raison de générer les deux juste pour le plaisir de remplir le dossier des artefacts.
Le plus important n’est de toute façon pas de savoir si votre XML est suffisamment moderne. Le vrai objectif reste d’avoir des tests capables de casser quand votre code casse. Un magnifique 97 % de coverage accompagné de tests qui ne vérifient rien restera toujours un très joli 97 % de pas grand-chose.