Intro à JaCoCo

1. Vue d’ensemble

  • La couverture de code ** est une métrique logicielle utilisée pour mesurer le nombre de lignes de notre code exécutées lors de tests automatisés.

Dans cet article, nous allons passer en revue certains aspects pratiques de l’utilisation de JaCoCo , un générateur de rapports de couverture de code pour les projets Java.

2. Configuration Maven

Afin de démarrer avec JaCoCo, nous devons déclarer ceci https://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.jacoco%22%20AND%20a%3A% 22jacoco-maven-plugin% 22[plugin maven]dans notre fichier pom.xml :

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.7.7.201606060606</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>report</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Le lien fourni ci-avant vous mènera toujours à la dernière version du plug-in dans le référentiel central maven.

3. Rapports de couverture de code

Avant de commencer à examiner les capacités de couverture de code de JaCoCo, nous avons besoin d’un échantillon de code. Voici une simple fonction Java qui vérifie si une chaîne lit le même en arrière et en avant:

public boolean isPalindrome(String inputString) {
    if (inputString.length() == 0) {
        return true;
    } else {
        char firstChar = inputString.charAt(0);
        char lastChar = inputString.charAt(inputString.length() - 1);
        String mid = inputString.substring(1, inputString.length() - 1);
        return (firstChar == lastChar) && isPalindrome(mid);
    }
}

Tout ce dont nous avons besoin maintenant est un simple test JUnit :

@Test
public void whenEmptyString__thenAccept() {
    Palindrome palindromeTester = new Palindrome();
    assertTrue(palindromeTester.isPalindrome(""));
}

L’exécution du test avec JUnit activera automatiquement l’agent JaCoCo et créera donc un rapport de couverture au format binaire dans le répertoire cible - target/jacoco.exec.

Évidemment, nous ne pouvons pas interpréter la sortie à elle seule, mais d’autres outils et plugins peuvent - par exemple.

La bonne nouvelle est que nous pouvons utiliser l’objectif jacoco: report afin de générer des rapports de couverture de code lisibles dans plusieurs formats - par exemple. HTML, CSV et XML.

Nous pouvons maintenant examiner par exemple la page target/site/jacoco/index.html pour voir à quoi ressemble le rapport généré:

couverture

En suivant le lien fourni dans le rapport - Palindrome.java , nous pouvons explorer une vue plus détaillée pour chaque classe Java:

image

Notez que vous pouvez facilement gérer la couverture de code en utilisant JaCoCo dans Eclipse avec une configuration zéro , grâce au EclEmma Eclipse plugin .

4. Analyse du rapport

Notre rapport indique une couverture d’instructions de 21%, de 17% de branches, 3/5 pour la complexité cyclomatique et ainsi de suite.

Les 38 instructions montrées par JaCoCo dans le rapport font référence aux instructions bytecode par opposition aux instructions de code Java ordinaires.

Les rapports JaCoCo vous aident à analyser visuellement la couverture de code en utilisant des diamants avec des couleurs pour les branches et des couleurs d’arrière-plan pour les lignes:

  • Le losange rouge signifie qu’aucune branche n’a été exercée pendant la

phase de test.

  • Le diamant jaune indique que le code est partiellement couvert - certains

les branches n’ont pas été exercées.

  • Le diamant vert signifie que toutes les branches ont été exercées au cours de la

tester.

Le même code de couleur s’applique à la couleur d’arrière-plan, mais pour la couverture des lignes.

JaCoCo fournit principalement trois mesures importantes:

  • La couverture des lignes reflète la quantité de code qui a été exercée

basé sur le nombre d’instructions de code octet Java appelées par les tests.

  • Couverture des branches indique le pourcentage de succursales exercées dans le

code - généralement lié aux instructions if/else et switch .

  • La complexité cyclomatique reflète la complexité du code en donnant au

nombre de chemins nécessaires pour couvrir tous les chemins possibles dans un code par combinaison linéaire.

Pour prendre un exemple trivial, s’il n’y a pas d’instructions if ou switch dans le code, la complexité cyclomatique sera de 1, car nous n’avons besoin que d’un seul chemin d’exécution pour couvrir tout le code.

Généralement, la complexité cyclomatique reflète le nombre de tests élémentaires à implémenter pour couvrir l’ensemble du code.

5. Répartition du concept

JaCoCo fonctionne comme un agent Java , il est responsable de l’instrumentation du bytecode lors de l’exécution des tests. JaCoCo explore chaque instruction et montre quelles lignes sont exercées lors de chaque test.

Pour collecter les données de couverture, JaCoCo utilise ASM pour l’instrumentation de code à la volée, recevant des événements de JVM Tool Interface dans le processus:

concept jacoco

Il est également possible d’exécuter l’agent JaCoCo en mode serveur. Dans ce cas, nous pouvons exécuter nos tests avec jacoco: dump comme objectif pour lancer une demande de vidage.

Vous pouvez suivre le official documentation link pour plus de détails sur la conception de JaCoCo.

6. Score de couverture de code

Maintenant que nous en savons un peu plus sur le fonctionnement de JaCoCo, améliorons notre score de couverture de code.

Afin d’atteindre une couverture de code à 100%, nous devons introduire des tests, qui couvrent les parties manquantes indiquées dans le rapport initial:

@Test
public void whenPalindrom__thenAccept() {
    Palindrome palindromeTester = new Palindrome();
    assertTrue(palindromeTester.isPalindrome("noon"));
}

@Test
public void whenNearPalindrom__thanReject(){
    Palindrome palindromeTester = new Palindrome();
    assertFalse(palindromeTester.isPalindrome("neon"));
}

Nous pouvons maintenant dire que nous avons suffisamment de tests pour couvrir l’ensemble du code, mais pour s’assurer de cela, exécutons la commande Maven mvn jacoco: report pour publier le rapport de couverture:

couverture

Comme vous pouvez le voir, toutes les lignes/branches/chemins de notre code sont entièrement couverts:

couverture

Dans les projets réels, et à mesure que les développements vont plus loin, nous devons garder le suivi du score de couverture de code.

JaCoCo offre un moyen simple de déclarer les exigences minimales à respecter, sinon la construction échouera.

Nous pouvons le faire en ajoutant l’objectif check suivant dans notre fichier pom.xml :

<execution>
    <id>jacoco-check</id>
    <goals>
        <goal>check</goal>
    </goals>
    <configuration>
        <rules>
            <rule>
                <element>PACKAGE</element>
                <limits>
                    <limit>
                        <counter>LINE</counter>
                        <value>COVEREDRATIO</value>
                        <minimum>0.50</minimum>
                    </limit>
                </limits>
            </rule>
        </rules>
    </configuration>
</execution>

Comme vous pouvez probablement le deviner, nous limitons ici le score minimum pour la couverture en lignes à 50%.

L’objectif jacoco: check est lié à verify . Nous pouvons donc exécuter la commande Maven - mvn clean verify pour vérifier si les règles sont respectées ou non. Les journaux montreront quelque chose comme:

----[ERROR]Failed to execute goal org.jacoco:jacoco-maven-plugin:0.7.7.201606060606:check
  (jacoco-check) on project mutation-testing: Coverage checks have not been met.
----

7. Conclusion

Dans cet article, nous avons vu comment utiliser JaCoCo maven plugin pour générer des rapports de couverture de code pour des projets Java.

Gardez cependant à l’esprit que la couverture de code à 100% ne reflète pas nécessairement l’efficacité des tests , car elle ne reflète que la quantité de code exercée au cours des tests. Dans un article précédent, nous avons parlé de test de mutation comme moyen plus sophistiqué de suivre l’efficacité des tests par rapport à la couverture de code ordinaire .

Vous pouvez consulter l’exemple fourni dans cet article dans le lien projet GitHub .