Objectifs:

  • découvrir l'automatisation des tests unitaires en Java avec les frameworks JUnit et JaCoCo (Java Code Coverage).
  • découvrir l'outil de construction de projets (build tool) Maven de la fondation Apache.

Quelques liens utiles pour compléter ce TP :

1. Créer un projet Java avec Maven sous VSCode

Maven est un outil logiciel qui vous aide à gérer des projets Java et à automatiser la création d'applications. L'extension Maven pour Java pour Visual Studio Code (intégrée au Java Extension Pack) fournit une prise en charge de Maven entièrement intégrée. Cette extension vous permet :

  • de générer des projets Maven à partir d'archétypes Maven,
  • d'explorer des projets Maven,
  • d'exécuter des commandes Maven (objectifs (goals) communs, objectifs de plugins, commandes personnalisées),
  • de conserver l'historique des commandes pour une réexécution rapide.

Pour découvrir l'utilisation de Maven sous VSCode, vous allez construire un projet simple que vous enrichirez dans les exercices suivants pour effectuer des tests unitaires avec Junit5. Les instructions suivantes détaillent les différentes étapes de cet exercice, que vous pouvez aussi retrouver dans une vidéo de 17min. : Créer un projet Maven avec VSCode

  1. Placez vous dans votre répertoire de travail POOJava
  2. Créez un répertoire TP07
  3. Positionnez vous dans le répertoire TP07.
  4. Lancez VSCode

  5. Dans la vue explorateur
    1. effectuez un clic droit
    2. dans le menu contextuel, sélectionnez l'item New Java Project

    Une alternative est de procéder comme suit

    1. Ouvrir la palette de commandes :(CTRL+Shift+P)
    2. Taper java
    3. dans la liste des commandes proposées choisir Java:Create Java Project...
  6. Dans les différentes manières de créer un projet Java choisir Maven create from archetype
  7. Choisissez l'archétype No Archetype qui vous permettra de créer directement un projet Java Maven avec une structure simple que vous pourrez facilement compléter pour la suite.
  8. Donnez ensuite un groupId à votre projet, ici fr.im2ag.m2cci.
  9. Rentrez ensuite l'artifactId de votre projet, ici compteur.
  10. VSCode vous demande d'indiquer un dossier (Folder) où ranger ce projet, sélectionnez le répertoire TP07.
  11. Une fenêtre d'alerte vous indiquant la création du projet est affichée, cliquez sur le bouton OK
  12. Le projet apparaît dans votre explorateur, ouvrez le fichier Main.java qui a été créé dans le dossier src du projet compteur. Une fois le fichier ouvert vous devriez avoir les éléments suivants dans votre fenêtre VSCode (cela peut prendre un certain temps, le temps que l'extension Java analyse le code).
  13. Ouvrez le fichier pom.xml, vous pouvez constater que le projet est configuré pour fonctionner avec une version 17 de Java (propriétés maven.compiler.source et maven.compiler.target). Remplacez les numéros de version par le numéro de version de votre JDK (si vous ne le connaissez pas, faites la commande java -version dans un terminal sur votre machine).
  14. Après l'avoir modifié, sauvegardez votre fichier pom.xml. L'assistant Maven de VSCode vous demande alors si vous voulez ou non mettre à jour le classpath de votre projet pour tenir compte de ces modifications, cliquez sur le bouton Yes.
  15. Dans la vue Java Projects
    1. faites un clic droit sur le package {} fr.im2ag.m2cci
    2. dans le menu contextuel sélectionnez l'item New
    3. dans le sous menu sélectionnez l'item Package
    4. saisissez le nom du nouveau package (fr.im2ag.m2cci.compteur)
    Une autre façon de procéder est de cliquer sur le bouton + situé à côté du package {} fr.im2ag.m2cci comme indiqué sur le figure ci-dessous.
  16. De la même manière, dans le package fr.im2ag.m2cci.compteur créez une nouvelle classe Java : Counter
  17. Modifiez le code source de cette classe, en le remplaçant par le code de Counter.java qui modélise un compteur entier (pour plus d'informations sur le fonctionnement de cette classe étudiez attentivement sa javadoc).
  18. Modifiez le programme principal situé dans la classe Main afin de créer deux compteurs et d'afficher leur somme.
  19. Exécutez ce programme et vérifiez que la somme affichée correspond bien à la valeur attendue.
    1. Dans l'application Main cliquez sur le bouton Run
    2. Dans le terminal, vérifiez que l'affichage produit est bien celui de la capture d'écran ci-dessous

2. Créer des tests unitaires JUnit avec Visual Studio Code

L'extension Java pour VSCode propose un support intégré pour la génération et l'exécution de tests unitaires à l'aide du framework JUnit (www.junit.org). Pour expérimenter avec cette fonctionnalité vous allez écrire les tests unitaires de la classe Counter vue dans l'exercice 1.

2.1 Configurer le projet pour utiliser JUnit5

Par défaut, la construction du projet avec sans archétype a généré un projet non configuré pour des tests effectués avec JUnit. Pour pouvoir utiliser JUnit5 (la dernière version du framework) il faut modifier le fichier de configuration du projet pom.xml.

Les instructions suivantes détaillent les différentes étapes de cet configuration

  1. Ouvrez le fichier pom.xml et rajoutez une dépendance vers la version de JUnit que vous souhaitez utiliser pour le projet (5.11.4 au 2 janvier 2025) dans un élément <dependencies> que vous insérerez après l'élément <properties>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.11.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
  2. Rajouter une dépendance à la dernière version du plugin maven-surefire-plugin en charge de l'exécution des tests (3.5.2 au 2 janvier 2025). Pour cela, rajoutez après l'élément dependencies un élément build avec le contenu suivant
    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.5.2</version>
            </plugin>
        </plugins>
    </build>
  3. Sauvegardez le fichier pom.xml et si VSCode vous le demande, synchronisez votre classpath pour prendre en consideration les modifications que vous venez d'effectuer.

2.2 Générer une classe de tests unitaires

Vous allez maintenant générer le code de la classe de test associée à la classe Counter.

  1. Effectuez un clic droit dans la fenêtre d'édition de Counter.java et sélectionnez l'éléments Source Action... dans le menu contextuel.
  2. Dans le sous menu qui apparait choisissez l'item Generate Tests...
  3. Spécifiez ensuite le nom de la classe de test générée (CounterTest).
  4. Demandez ensuite la génération des cas de tests pour chacune des méthodes de la classe Counter en cochant toutes les méthodes.

Dans son organisation standard pour les projets Java, Maven sépare le code source des classes de votre application (répertoire src/main/java) du code source des classes de test (répertoire test/src/java).

Pour chacune des méthodes de la classe Counter une méthode de test correspondante a été produite dans le fichier CounterTest.java. Pour le moment toutes les méthodes de test (méthodes précédées de l'annotation @Test) ont un corps vide, vous devrez bien entendu compléter ce code par la suite pour y ajouter vos tests.

2.3 Exécuter les tests unitaires

L'exécution des test unitaires peut se faire depuis un terminal en tapant la commande mvn test (Attention il faut se placer dans le répertoire compteur).

Il est egalement possible de le faire en utilisant les extensions Java de VSCode. Pour cela vous pouvez procéder comme suit :

  1. Dans la barre d'outils sélectionnez l'outil testing qui permet d'afficher la vue Testing qui regroupe les différentes classes de test de votre projet et pour chacune d'elles les différents cas de test proposés.
  2. Dans cette vue, sélectionnez la classe CounterTest et cliquez sur le bouton Run Test associé

L'exécution de toutes les méthodes de test de la classe CounterTest est lancée

Vous pouvez constatez que tous les tests passent avec succès, ce qui est normal toutes les méthodes de test ne comportant aucune instruction. On peut regretter que le générateur de code ait adopté cettevstratégie, il aurait, à mon avis, été préférable de faire en sorte que tous les cas de tests échouent. Nous verrons cela dans l'exercice qui suit.

2.4 Ecriture des cas de test

Exercice: complétez la classe CounterTest pour que chacune des fonctionnalités de la classe Counter soit testée.

  1. Commencez par écrire une méthode de test pour l'addition en remplaçant le code généré par :

    @Test
    public void testAdd() {
        System.out.println("add");
        Counter c1 = new Counter(10);
        Counter c2 = new Counter(4);
        Counter c3 = c1.add(c2);
        assertEquals(14, c3.getCount());
        assertEquals(10, c1.getCount());
        assertEquals(4, c2.getCount());
    }
  2. Pour toutes les autres méthodes de test, faites en sortent qu'elle échouent en ajoutant une instruction fail(); dans leur corps, comme dans l'exemple ci-dessous.
    @Test
    void testDecrement() {
        fail("test pas encore implémenté");
    }
  3. Relancez les tests de la classe et vérifiez que le cas de test testAdd passe alors que tous les autres cas de test échouent.

    Modification de la classe CompteurTest et réexécution des tests.
  4. Ecrivez le code pour les autres cas de test (vous pouvez vour référer à la javadoc de la classe Assertions de JUnit afin de voir les différents types d'assertions possibles). La classe Counter contient des bugs; découvrez les avec les tests unitaires, corrigez les et vérifiez que TOUS vos tests réussissent.

3. Ajout d'un outil de couverture de code

Une fois que tous les cas de test ont été exécutés avec succès pour la classe CounterTest, vous vous allez pouvoir ajouter à votre environnement de développement un outil de couverture de code: JaCoCo (Java CodeCoverage).

3.1 Declaration du plugin JaCoCo dans le fichier pom.xml

Un plugin maven (jacoco-maven-plugin) permet d'utiliser l'outil de converture de code lors de l'exécution des tests du projet maven d'application java. Afin de l'utiliser, il vous faut à nouveau modifier le fichier pom.xml qui définit la configuration de votre projet.

  1. Ouvrez le fichier pom.xml à la fin de celui-ci, entre la balise fermante </pluginManagement> et la balise fermante </build> ajoutez un élément plugins pour intégrer le plugin maven dédié à jaCoCo :

    le code à insérer

    <plugin>
        <groupId>org.jacoco</groupId>
        <artifactId>jacoco-maven-plugin</artifactId>
        <version>0.8.12</version> <!-- dernière version du plugin au 05/01/2025 -->
        <executions>
            <execution>
                <id>default-prepare-agent</id>
                <goals>
                    <goal>prepare-agent</goal>
                </goals>
            </execution>
            <execution>
                <id>jacoco-report</id>
                <phase>test</phase>
                <goals>
                    <goal>report</goal>
                </goals>
            </execution>
        </executions>
    </plugin>
  2. Sauvegardez le fichier pom.xml et mettez à jour le classpath et la configuration de votre application.

3.2 Lancement des tests avec couverture de code

Une fois le plugin jacoco-maven-plugin installé vous pourrez lancer les tests avec un calcul de couverture de code en passant par Maven.

  1. Avant de lancer les tests avec JaCoCo rajoutez à votre classe Counter la méthode suivante :

        /**
         * Création d'un nouveau compteur dont la valeur est le produit entre la
         * valeur de ce compteur et celle du compteur passé en paramètre
         *
         * @param c le compteur à multiplier avec ce compteur
         * @return le compteur créé
         */
        public Counter mult(Counter c) {
            return new Counter(this.count * c.count);
        }
  2. Dans la vue Maven sélectionnez et exécutez la cible (goal) clean pour nettoyer votre projet, c'est dire supprimer tous les fichiers générés par la compilation du projet et les exécutions précédentes des tests situés dans le repertoire target.

  3. Faites de même pour exécuter la cible test. Les tests sont lancés et JaCoCoverage instrumente la machine virtuelle Java pour mesurer la couverture de code puis une fois les tests terminés génère un rapport de tests. Vous pouvez voir cela dans le terminal où s'affiche la trace d'exécution de la phase test.
  4. Vous pouvez accéder aux rapports de couverture du code de votre projet en ouvrant dans un navigateur le fichier index.html situé dans le sous répertoire site/jacoco du dossier target (dont le contenu est généré par Maven).

3.2 Ajouter l'extension Coverage Gutters à VSCode

Vous pouvez aussi visualisez la couverture de code directement dans l'éditeur de VSCode pour cela, il vous faut installer une extension capable d'exploiter les données récupérées par JaCoCo, par exemple l'extension Coverage Gutters

le site web de Coverage Gutters
Page web de l'extension Coverage Gutters sur VSCode Market Place

Une fois l'extension Coverage Gutters installée (et les tests exécutés par Maven)

  1. Ouvrez le fichier Counter.java dans l'éditeur de VSCode
  2. Cliquez sur le bouton Watch pour observer la couverture de code sur cette classe
  3. Vous pouvez alors voir les instructions qui ont été exécutées pendant le test, et celles qui ne l'ont pas été ainsi que le taux de couverture de code de vos tests.
  4. Par défaut seules un bande rouge ou verte à gauche des numéros de lignes indiquent les instructions qui ont été exécutées, ce qui n'est pas très visible en modre sombre (dark). Il est possible de modifier la configuration de l'extension coverage_gutters afin de coloriser l'ensemble des lignes pour rendre l'affichage de la couverture de code plus visible.
    couverture du code
    Pour obtenir un affichage comme ci-dessus, il faut modifier la configuration de l'extension Coverage Gutters en procédant comme suit.
    couverture du code
  5. En cliquant à nouveau sur le bouton Watch, vous pouvez masquer la couverture de code dans l'éditeur.

Exercice : assurez-vous que les tests unitaires de la classe Counter offrent une totale couverture de code (100%).

4. Ecriture des tests unitaires de la classe Rational

Exercice: Ecrivez le code JUnit5 permettant de tester les classes Rational et SequenceRationals vues dans le TP 4. Bien entendu, vous vérifierez que vos tests unitaires assurent une totale couverture de code. Pour cela procédez comme suit :

  1. créez dans le répertoire TP07 un second projet maven (rationals)
    creation du projet rationals
    creation du projet rationals
  2. créez un package fr.im2ag.m2cci.rationals
    creation du projet rationals
  3. Recopiez le code source de la classe Rational dans le package fr.im2ag.m2cci.rationals Pour importer la classe Rationals, vous pouvez soit prendre celle que vous avez réalisée, soit celle de la correction du TP4 accessible sur gitlab. Dans ce cas vous pouvez procéder comme suit :
    creation du projet rationals
    Attention, n'oubliez pas de définir le package d'appartenance dans le code source de la classe Rational
    creation du projet rationals
    De la même manière rajoutez à votre projet le code de la classe SequenceRationals
  4. modifiez le fichier pom.xml (version de JDK, dépendances JUnit5, mise à jour du n° de version de maven-surfire-plugin, ajout du plugin pour jaCoCo...),
  5. générez la classe de test pour (RationalTest), et faites en sorte que tous les tests échouent en mettant un assertion fail() dans chacun des cas de test (dommage que le générateur de tests ne le fasse pas par défaut).
  6. écrivez chaque méthode de test (ne pas écrire tous les tests puis tester, mais écrivez une méthode de test et vérifiez que le test passe avant d'écrire la méthode de test suivante),
  7. lorsque tous les tests passent avec succès, vérifiez que la couverture du code pour la classe Rational est bien de 100%. Si ce n'est pas le cas complétez vos test

5. Pour aller plus loin

Si vous voulez en faire un peu plus et vous entrainer, écrivez des test unitaires JUnit5 pour la classe Ensemble de Lettres vue au TP 5 et la classe Compte bancaire vue au TP 6