L'objectif est de clarifier ce que mesure réellement la couverture de code, ainsi que ses limites.
Nous mettons en place "JaCoCo", configuré avec la génération de rapports (HTML/XML) et nous définissons le seuils de couverture en pilotant des exigences différentes, selon les branches via GitHub Actions. Enfin nous verrons comment intégrer "SonarCloud" tout en restant compatible avec les contraintes du plan gratuit
Mesurer et garantir la qualité du code de manière automatisée
JaCoCo analyse quelles sont les parties du code source qui sont réellement exécutées lors des tests (unitaires, d'intégration ou E2E)
→ Il génère ensuite des rapports détaillés montrant les lignes couvertes (vert), partiellement couvertes (jaune) ou non testées (rouge) Réduire les bugs en production
Diminuer la dette technique
Vérifier les validations
→ Il s'intègre naturellement avec SonarQube et d'autres outils d'analyse.

La distinction est subtile mais importante: les tests sont l'action de vérifier, tandis que la couverture est la mesure de cette action
Sont des scénarios créés par les développeurs pour valider que le logiciel fonctionne comme prévu. L'objectif est de détecter des bugs, valider des fonctionnalités ou des exigences métier
La Mesure (calculée par des outils comme JaCoCo) est une métrique quantitative. Elle mesure le pourcentage de lignes, de branches ou d'instructions exécutées par les tests
Passer de 0 % à 70 % de couverture apporte énormément de valeur.
Passer de 95 % à 100 % coûte très cher pour un gain de fiabilité souvent faible.
La couverture suit la structure du code (les lignes).
Elle n'a aucune idée des fonctionnalités manquantes.
L'idée n'est pas d'atteindre 80% partout, tout de suite, mais de ne jamais régresser
Seuil sur le "Nouveau Code"
On accepte une couverture globale faible (par exemple 30 %), mais on exige 80 % sur les lignes modifiées (diff coverage)
Ce principe est au cœur de la méthodologie "Clean as You Code" de SonarQube/SonarCloud
Des seuils progressifs sont appliqués via la CI, afin d'illustrer une approche réaliste en contexte professionnel
| Branche | Seuil | Mode | Objectif |
|---|---|---|---|
| develop | - | non-bloquant | Feedback uniquement: Informer, habituer l'équipe, ne jamais casser le flux |
| staging | 70% | bloquant | Qualité projet: éviter la régression et stabiliser le socle |
| main | 80% | bloquant + SonarQube | Gate finale: standard “enterprise” et utilisation de métrique officielle |
<properties>
<jacoco.plugin.version>0.8.11</jacoco.plugin.version>
<jacoco.check.skip>false</jacoco.check.skip>
<jacoco.minimum.coverage>0.0</jacoco.minimum.coverage>
//..
<sonar.plugin.version>4.0.0.4121</sonar.plugin.version>
<sonar.projectKey>val7304_flashcards</sonar.projectKey>
<sonar.organization>val7304</sonar.organization>
<sonar.projectName>flashcards</sonar.projectName>
<sonar.coverage.exclusions>
**/FlashcardsApplication.java,
**/*Configuration.java,
**/*Config.java,
**/dto/**
</sonar.coverage.exclusions>
<sonar.coverage.jacoco.xmlReportPaths>${project.build.directory}/site/jacoco/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>
</properties>
<jacoco.minimum.coverage> sera surchargé par les pipelines (develop / staging / main)
<!-- JaCoCo -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<executions>
<!-- active agent -->
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
//...
Le plugin JaCoCo Maven doit attacher l'agent pendant les tests (prepare-agent)
De là, il va générer les rapports HTML/XML (point3)
Il peut faire échouer le build si la couverture minimale n'est pas atteinte (check avec COVEREDRATIO au point5)
<!-- HTML/XML -->
<execution>
<id>report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<!-- check -->
<execution>
<id>jacoco-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<!-- desactive localement: -Djacoco.check.skip=true -->
<skip>${jacoco.check.skip}</skip>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.minimum.coverage}</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- Sonar -->
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>4.0.0.4121</version>
</plugin>
<profiles>
<profile>
<id>coverage-staging</id>
<properties>
<jacoco.minimum.coverage>0.70</jacoco.minimum.coverage>
</properties>
</profile>
<profile>
<id>coverage-main</id>
<properties>
<jacoco.minimum.coverage>0.80</jacoco.minimum.coverage>
</properties>
</profile>
</profiles>
Ces profils illustrent une approche avancée permettant de simuler localement le comportement des pipelines staging et main
./mvnw clean verify -Pcoverage-staging
./mvnw clean verify -Pcoverage-main
L'autre option est utiliser les mêmes commandes qu'en CI:
./mvnw clean verify -Djacoco.minimum.coverage=0.70
./mvnw clean verify -Djacoco.minimum.coverage=0.80
Même code sur toutes les branches
Règles différentesLa couverture de test doit être mesurée partout, mais imposée uniquement aux points de contrôle du cycle de vie applicatif
Le contrôle de couverture intervient en phase verify, après l'exécution des tests et la génération du package
- name: Run Maven clean verify
run: ./mvnw -B clean verify jacoco:report
- name: Upload JaCoCo report
uses: actions/upload-artifact@v6
with:
name: jacoco-report
path: target/site/jacoco/
La commande clean verify lance tous les tests
En dev le seuil n'est pas fixé, c'est à dire qu'il faut le tester avec les commandes CI ou les profils
- name: Verify Coverage 70%
run: ./mvnw -B clean verify jacoco:report -Djacoco.minimum.coverage=0.70
- name: Upload JaCoCo artifacts
uses: actions/upload-artifact@v6
with:
name: jacoco-report
path: |
target/site/jacoco/index.html
target/site/jacoco/jacoco.xml
./mvnw clean verify
-Djacoco.minimum.coverage=0.70
./mvnw clean verify -Pcoverage-staging
- name: Build + Tests + Coverage gate (release)
if: env.IS_RELEASE == 'true'
run: ./mvnw -B clean verify -Djacoco.minimum.coverage=0.80
- name: Build + Unit tests only (non-release)
if: env.IS_RELEASE != 'true'
run: ./mvnw -B clean test jacoco:report
- name: Upload JaCoCo XML
uses: actions/upload-artifact@v6
with:
name: jacoco-xml
path: target/site/jacoco/jacoco.xml
- name: SonarCloud analysis
if: github.ref == 'refs/heads/main'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: >
./mvnw sonar:sonar
-Dsonar.host.url=https://sonarcloud.io
-Dsonar.organization=val7304
-Dsonar.projectKey=${{ secrets.SONAR_PROJECT_KEY }}
-Dsonar.qualitygate.wait=true
Pareil qu'en staging:
./mvnw clean verify
-Djacoco.minimum.coverage=0.80
Ou, si vous avez paramétré le profil, utilisez:
./mvnw clean verify -Pcoverage-main
Avec l'argument -Djacoco.minimum.coverage=0.80, on bloque le pipeline si la couverture est insuffisante
Si les tests passent et que le seuil est respecté, le rapport JaCoCo est produit et uploadé, ensuite SonarCloud s'en sert pour démarrer ses analyses
Avec le plan gratuit SonarCloud, on ne peux analyser qu'une seule branche “complète”: la branche principale.
Les autres branches (develop, staging, feature/…) sont visibles via les analyses de Pull Requests vers cette branche
Sur [main]: Chaque scan met à jour la base de référence (couverture, bugs, vulnérabilités, dette) du projet
Sur [develop] & [staging]: On analyse via des PR (vers main) et on voit la couverture et la qualité sur le "nouveau code" de ces branches
mvn sonar:sonar \
-Dsonar.projectKey=YOUR_PROJET \
-Dsonar.organization=YOUR_ORG \
-Dsonar.host.url=https://sonarcloud.io \
-Dsonar.cache.enabled=true \
-Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml
→ En local: On peut ouvrir le rapport et voir ainsi la couverture détaillée de toutes les classes
→ Sur une PR: SonarCloud nous montre si les nouvelles lignes sont couvertes par des tests
Si on ajoute 10 lignes, Sonar analyse la couverture du “New Code” définie par la branche cible et compare les métriques au Quality Gate.
→ Sur main: après le merge, une analyse complète met à jour la couverture globale et les métriques de qualité du projet
En pratique, JaCoCo vous donne une mesure factuelle des zones non testées, là où SonarCloud fournit la vue d'ensemble (bugs, vulnérabilités, dette)
Dans l'article suivant, nous verrons comment poser les bases (branche unique) pour un premier pipeline (main)