Aller au contenu

TP4 - Les tests unitaires⚓︎

Source : Wikipedia

Ce qui suit est fortement insipiré de cette page.

1. Présentation⚓︎

Un test unitaire (TU ou UT en anglais) consiste à isoler une partie du code et à vérifier qu'il fonctionne parfaitement. Il s'agit de petits tests qui valident l'attitude d'un objet et la logique du code.

Dans les applications non critiques, l'écriture des TU a longtemps été considérée comme une tâche secondaire. Cependant, les méthodes Extreme programming (XP) ou Test Driven Development (TDD) ont remis les tests unitaires, aussi appelés « tests du programmeur », au centre de l'activité de programmation.

Les TU sont encore considéré comme une perte de temps par certain développeurs. Mais ils permettent en fait un gain de temps, d'énergie et d'argent vraiment important. Ils sont un point central dans toutes les méthodes modernes de developpement.

2. Utilité⚓︎

On écrit un test pour confronter une réalisation à sa spécification. Il permet de vérifier que pour un certain nombre de données en entrée, le résultat en sortie est bien celui attendu. Il a principalement trois utilités :

  1. Trouver les erreurs rapidement
    La méthode XP préconise d'écrire les tests en même temps, ou même avant la fonction à tester (Test Driven Development). Ceci permet de définir précisément l'interface du module à développer. Les tests sont exécutés durant tout le développement, permettant de visualiser si le code fraîchement écrit correspond au besoin.
  2. Sécuriser la maintenance
    Lors d'une modification d'un programme, les tests unitaires signalent les éventuelles régressions. En effet, certains tests peuvent échouer à la suite d'une modification, il faut donc soit réécrire le test pour le faire correspondre aux nouvelles attentes, soit corriger l'erreur se situant dans le code.
    Ceci est un problème important dans le developpement de programme de grande taille où de nombreux développeurs interviennent. Il arrive fréquemment qu'une modification anodine du code existant, pour permettre l'ajout d'une nouvelle fonctionnalité par exemple, impacte sans qu'on s'en rende compte une ancienne fonctionnalité, qui présente alors des bugs.
    L'absence de tests unitaires automatisés rend très difficile la découverte de ces régressions avant le déploiement de l'application.
  3. Documenter le code
    Les tests unitaires peuvent servir de complément à l'API, il est très utile de lire les tests pour comprendre comment s'utilise une méthode. De plus, il est possible que la documentation ne soit plus à jour, mais les tests eux correspondent nécessairement à la réalité de l'application.

3. Fonctionnement⚓︎

On définit généralement 4 phases dans l'exécution d'un test unitaire :

  1. Initialisation (fonction setUp) : définition d'un environnement de test complètement reproductible.
  2. Exercice : le module à tester est exécuté.
  3. Vérification (utilisation de fonctions assert) : comparaison des résultats obtenus avec un vecteur de résultat défini. Ces tests définissent le résultat du test : succès ou échec.
  4. Désactivation (fonction tearDown) : désinstallation de ce qui a éventuellement pu être mis en place dans l'initialisation, pour retrouver l'état initial du système, dans le but de ne pas polluer les tests suivants. Tous les tests doivent être indépendants et reproductibles unitairement (quand exécutés seuls).

Une classe de test comporte éventuellement une méthode setUp, éventuellement une méthode tearDown, et autant de méthodes test (c'est-à-dire les phases 2 et 3 ci-dessus) que souhaité. Chacune des méthodes test doit être indépendante des autres, et elles doivent pouvoir être exécutées dans n'importe quel ordre. Les méthodes setUp et tearDown sont appellées respectivement avant et après chaque appel d'une méthode test. Les méthodes setUp et tearDown ne doivent donc être implémentées que si toutes les méthodes de test ont besoin d'exécuter un même traitement avant et après le test. On peut par exemple penser à la connexion à une base de données (dans la méthode setUp) qui doit être fermée à la fin de chaque test (dans la méthode tearDown).

Pour aller plus loin - Utilisation de mocks

Dans une application avec une architecture complexe, dans laquelle il y a de nombreuses dépendances entre les différents objets, il devient compliqué d'écrire des tests unitaires permettant de ne tester qu'une seule fonctionnalité, isolée des autres.

Il existe des outils permettant de simuler une dépendance (c'est-à-dire un autre objet) de manière contrôlée : les mocks.

Vous trouverez un début d'explication sur la page Wikipedia.

Le framework java mockito permet d'utiliser des mocks dans les TU.

4. Installation⚓︎

Nous utiliserons l'IDE eclipse pour les développements.

Nous allons continuer d'utiliser le projet Java TPCollections créé dans le TP précédent. Dans ce projet, à la racine, créer un dossier 📂lib, dans lequel nous placerons les dépendances du projet (les bibliothèques externes, sous forme de JAR).

Nous allons utiliser l'API JUnit pour mettre en place les tests unitaires en Java.

Deux versions de JUnit sont utilisées, la 4 et la 5. Nous utiliserons d'abord la 4, qui est plus simple à configurer manuellement.

Lorsqu'on doit utiliser une API, on peut (souvent) trouver les JAR correspondant dans le dépôt maven, présent ici. Une recherche de junit affiche les différentes API disponibles. Celle qui nous interesse, qui correspond à JUnit4, est celle appelée JUnit (le deuxième résultat normalement). Lorsqu'on clique sur ce résultat, on obtient la liste des différentes versions disponibles. On peut cliquer sur la dernière (la 4.13.2), et il est alors possible de cliquer sur jar pour le télécharger.

Mais l'utilisation d'un JAR nécessite parfois la présence d'autres JARs. Maven permet de trouver ces dépendances. En descendant un peu, dans la partie Compile Dependencies, on trouve :

Dépendances pour JUnit4

Il faut donc cliquer sur ce lien, et télécharger la version 1.3 de cette API.

Ce JAR n'a pas de dépendance, on peut donc s'arrêter là.

Il ne reste maintenant plus qu'à associer ces deux bibliothèques au projet :

  1. Déplacer les deux JAR dans le dossier 📂lib créé juste précédemment.
  2. Ajouter ces deux JAR dans le classpath du projet. Pour cela, accéder au propriétés du projet, aller dans Java Build Path > Libraries > Classpath. Cliquer sur le bouton Add JARs..., sélectionner les 2 JAR, puis cliquer sur Ok et Apply and Close.

5. Fonctionnement avec JUnit⚓︎

Avec JUnit3, une classe de test devait hériter de junit.framework.TestCase, et il fallait redéfinir les méthodes setUp et tearDown pour définir des traitements exécutés systématiquement avant et après chaque cas de tests.

JUnit4 propose simplement d'annoter la méthode exécutée avant avec l'annotation @Before et la méthode exécutée après avec l'annotation @After. Chaque cas de test correspond à une méthode annotée avec @Test. La classe de test n'a plus à hériter de le classe TestCase.

6. Exercices⚓︎

Exercice 1 - Prise en main

Dans cet exercice, nous allons reprendre ce que nous avions développé dans le projet précédent, en automatisant les tests.

Nous allons donc créer une classe TestNotes, qui contiendra nos jeux de tests sur la classe Notes. Comme dans le TP précédent, cette classe sera dans le même package que les classes qu'elle permet de tester, c'est-à-dire fr.univtours.polytech.tpcollections. Cependant, contrairement à ce que nous avons fait dans le TP précédent, il est préférable de ne pas mélanger la partie "développement de l'application" et la partie "test". Pour cela, nous allons créer un deuxième dossier de sources (Source Folder), nommé test, qui contiendra également le package fr.univtours.polytech.tpcollections.

Voici donc à quoi doit maintenant ressembler l'arborescence du projet :

    TPCollections/
    ├── src/
    │   └── fr/
    │       └── univtours/
    │           └── polytech/
    │               └── tpcollections/
    │                   ├── Notes.java
    │                   ├── Student.java
    │                   ├── Subject.java
    │                   └── YearGroup.java
    ├── test/
    │   └── fr/
    │       └── univtours/
    │           └── polytech/
    │               └── tpcollections/
    │                   └── TestNotes.java
    └── lib/
        ├── hamcrest-core-1.3.jar/
        └── junit-4.13.2.jar/

Nous allons tout d'abord tester la méthode addNotes(). Nous allons vérifier que si nous appelons deux fois cette méthode, l'objet contient bien 2 notes ensuite.

Chaque test unitaire est indépendant des autres. Cela signifie que toutes les méthodes annotées @Test sont exécutées dans n'importe quel ordre, et ne doivent pas avoir de dépendances entre elle.

Ici, il faut donc définir le contexte, c'est-à-dire les objets nécessaires au test, dans le test unitaire :

☕ Code Java
@Test
public void testAddNote() {
    Notes notes = new Notes();
    notes.addNote(15D);
    notes.addNote(16D);
    //(1)!

    assertEquals(2, notes.getNotesList().size());
}
  1. Ici, on a défini le contexte de notre test.

Enfin, il ne nous reste plus qu'à exécuter le test. Pour cela, dans l'arborescence du projet, faire un clic droit sur la classe, puis Run as > JUnit Test.

Nommage de tests unitaires

Il existe différentes règles pour nommer les méthodes de tests. Pour l'instant, on peut utiliser celle-ci : test[nomMéthode]_[leCasTesté]_[throwsException].

Un onglet Junit apparaît, indiquant le nombre de tests effectués, le nombre d'échecs (la méthode s'est exécutée sans erreur, mais n'a pas renvoyé ce qui était prévu) et le nombre d'erreurs (la méthode a levé une exception).

On peut ajouter autant de tests unitaires que souhaité, c'est-à-dire de méthode avec l'annotation @Test. Par exemple, on peut également tester la méthode computeMean() de la classe Notes. A nouveau, il faut commencer par définir le contexte :

☕ Code Java
@Test
public void testComputeMean() {
    Notes notes = new Notes();
    notes.addNote(15D);
    notes.addNote(16D);

    assertEquals(15.5D, notes.computeMean());
}
Ambigous method

Dans le cas présent, il existe deux méthodes assertEquals aux signatures proches qui peuvent être exécutées : assertEquals(double, double) et assertEquals(Object, Object).

Le code assertEquals(notes.computeMean(), 15.5D) va générer l'erreur suivante : The method assertEquals(Object, Object) is ambiguous for the type TestTP. Cela signifie que le compilateur ne sait pas laquelle des deux méthodes utiliser. Il faut donc être plus précis. Pour comparer deux double, il faut donc écrire, au choix :

  1. assertEquals(Double.valueOf(15.5D), notes.computeMean()) : la méthode assertEquals(Object, Object) est utilisée.
  2. assertEquals(15.5D, notes.computeMean().doubleValue()) : la méthode assertEquals(double, double) est utilisée. Dans ce cas, on constate que la méthode est obsolète (deprecated), donc on utilisera plutôt la première solution.

Lorsqu'on exécute la classe de test, on observe qu'il y a maintenant deux tests.

Ici, on constate que le contexte est exactement le même pour les deux tests. Il est possible de le mutualiser. Pour cela, nous allons ajouter une méthode avec l'annotation @Before, ce qui signifie qu'elle est appelée avant l'exécution de chaque test.

Notre classe de test devient donc :

☕ Code Java
private Notes notes;

@Before
public void setUp() {
    this.notes = new Notes();
    this.notes.addNote(15D);
    this.notes.addNote(16D);
}

@Test
public void testAddNote() {
    assertEquals(2, this.notes.getNotesList().size());
}

@Test
public void testComputeMean() {
    assertEquals(Double.valueOf(15.5D), this.notes.computeMean());
}
Exercice 2 - Tester la survenue d'une exception

Lors d'une développement d'une application, on souhaite souvent tester qu'une exception est bien levé dans une situation donnée.

JUnit permet de faire cela.

Supposons par exemple qu'on souhaite lever une ArithmeticException lorsqu'on souhaite calculer une moyenne alors qu'aucune note n'a été saisie (on fait en effet une division par 0 dans ce cas). Nous allons donc modifier la méthode computeMean() de la classe fr.univtours.polytech.tpcollections.Notes :

☕ Code Java
public Double computeMean() {
    // S'il n'y a pas de note ...
    if (this.notesList.size() == 0) {
        // ... on lève une exception.
        throw new ArithmeticException();
    }

    Double mean = 0D;

    for (Double note : this.notesList) {
        mean += note;
    }

    return mean / this.notesList.size();
}
Tester la survenue d'une exception

On peut tester que l'appel de la méthode doStuff lève bien l'exception ExpectedException en utilisant des expressions lambda. On utilise pour cela le code assertThrows(ExcpectedException.class, () -> doStuff());.

En respectant le point ci-dessus, pour tester la survenue de l'exception, et en respectant la règle de nommage décrite plus haut, nous allons ajouter la méthode suivante à notre classe de test :

☕ Code Java
@Test
public void testComputeMean_pasDeNote_throwsArithmeticException() {//(1)!
    this.notes = new Notes();
    assertThrows(ArithmeticException.class, () -> this.notes.computeMean());
}
  1. Le nom de la méthode respecte ce qui a été précisé plus haut.

Tester son bon fonctionnement.

Exercice 3 - Exécution de tous les tests unitaires d'un projet

On peut créer autant de classes de test que souhaité.

Un des (nombreux) intérêts de JUnit est qu'elles peuvent facilement être toutes exécutées simultanément.

Nous allons créer une deuxième classe de test, pour tester la classe YearGroup (ce sont en fait les tests que nous avions mis dans la classe TestNotesFinal dans le TP3). Nous allons donc appeler cette classe TestYearGroup.

Créons donc la classe fr.univtours.polytech.tpcollections.TestYearGroup :

Le code de TestYearGroup
☕ Code Java
public class TestYearGroup {

    private YearGroup yearGroup;
    private Subject info;
    private Subject maths;
    private Student alice;
    private Student bob;
    private Student charlie;

    @Before
    public void setUp() {
        // Création de deux matières :
        this.info = new Subject("Informatique", 1D);
        this.maths = new Subject("Mathématiques", 2D);

        // Création de 3 étudiants :
        this.alice = new Student("Alice");
        this.bob = new Student("Bob");
        this.charlie = new Student("Charlie");

        List<Student> students = new ArrayList<Student>();
        students.add(alice);
        students.add(bob);
        students.add(charlie);

        // Création de la promotion :
        this.yearGroup = new YearGroup();
        yearGroup.setYear(2022);
        yearGroup.setStudents(students);

        // Alice a 14 en info et 20 en maths.
        Notes aliceEnInfo = new Notes();
        aliceEnInfo.addNote(14D);
        alice.getNotesList().put(info, aliceEnInfo);
        Notes aliceEnMaths = new Notes();
        aliceEnMaths.addNote(20D);
        alice.getNotesList().put(maths, aliceEnMaths);

        // Bob a 16 en info et 10 en maths.
        Notes bobEnInfo = new Notes();
        bobEnInfo.addNote(16D);
        bob.getNotesList().put(info, bobEnInfo);
        Notes bobEnMaths = new Notes();
        bobEnMaths.addNote(10D);
        bob.getNotesList().put(maths, bobEnMaths);

        // Charlie a 15 en info et 15 en maths.
        Notes charlieEnInfo = new Notes();
        charlieEnInfo.addNote(15D);
        charlie.getNotesList().put(info, charlieEnInfo);
        Notes charlieEnMaths = new Notes();
        charlieEnMaths.addNote(15D);
        charlie.getNotesList().put(maths, charlieEnMaths);
    }

    @Test
    public void testComputeGroupMean() {
        assertEquals(Double.valueOf(15D), this.yearGroup.computeGroupMean());
    }

    @Test
    public void testComputeSubjectMean() {
        assertEquals(Double.valueOf(15D), this.yearGroup.computeSubjectMean(this.maths));
        assertEquals(Double.valueOf(15D), this.yearGroup.computeSubjectMean(this.info));
    }

    @Test
    public void testGetGroupRanking_premier() {
        assertEquals(this.alice, this.yearGroup.getGroupRanking().get(0));
    }

    @Test
    public void testGetGroupRanking_dernier() {
        int nbOfStudents = this.yearGroup.getStudents().size();
        assertEquals(this.bob, this.yearGroup.getGroupRanking().get(nbOfStudents - 1));
    }

    @Test
    public void testComputeGetBestNote() {
        assertEquals(Double.valueOf(20D), this.yearGroup.getBestNote(this.maths));
        assertEquals(Double.valueOf(16D), this.yearGroup.getBestNote(this.info));
    }

    @Test
    public void testComputeGetWorseNote() {
        assertEquals(Double.valueOf(10D), this.yearGroup.getWorseNote(this.maths));
        assertEquals(Double.valueOf(14D), this.yearGroup.getWorseNote(this.info));
    }
}

Pour exécuter tous les tests unitaires d'un projet, ll suffit alors de faire un clic droit sur le projet, et de l'exécuter en tant que "JUnit Test".

Exercice 4 - L'horloge

Le but est ici de simuler une horloge, qui indique donc une heure donnée (heure, minute et seconde), et à laquelle on peut ajouter autant de secondes que souhaité.

Voici le diagramme de cette classe :

classDiagram
    Horloge
    class Horloge{
        -heures: Integer
        -minutes: Integer
        -secondes: Integer
        +Horloge(heures: Integer, minutes: Integer, secondes: Integer)
        +getHeures() Integer
        +getMinutes() Integer
        +getSecondes() Integer
        +addSecondes(secondes: Integer)
    }

Test Driven Development

Dans cet exercice, nous allons utiliser la méthode de développement Test Driven Development, ou développements pilotés par les tests en français.

Cela signifie que nous allons d'abord écrire les tests, avant d'écrire le code de l'horloge.

Ainsi, les tests échouent au début, et doivent tous réussir au fur et à mesure des développements.

  1. Implémenter la classe fr.univtours.polytech.horloge.Horloge, sauf la méthode addSeconde qui pour l'instant ne fait rien.
  2. Implémenter les tests avec JUnit, et vérifier qu'ils ne passent pas pour le moment.
  3. Implémenter la méthode addSeconde de la classe fr.univtours.polytech.horloge.Horloge.
  4. Vérifier que tous les tests passent correctement.
Pour aller plus loin

L'appel de la méthode addSeconde avec un argument négatif (par exemple -3600) donne-t-il le résultat attendu ? Aviez-vous prévu ce test dès la question 2 ?

7. Introduction à Maven⚓︎

Nous allons maintenant utiliser JUnit5. Nous n'allons pour cela pas télécharger les JARs à la main, car il y a de nombreuses dépendances! Il faudrait en télécharger 12 rien que pour la version de base. Nous allons utiliser maven, qui va gérer automatiquement toutes ces dépendances pour nous.

Maven est un outil de gestion de projet développé par la fondation Apache. Il permet d'automatiser de nombreuses tâches.

Pour cela, dans eclipse, nous allons créer un projet maven (et non un projet java comme précédemment). Il faut cocher la case "Create à simple project (skip archetype selection)" :

Dépendances pour JUnit4

Un projet maven est identifié par 3 informations :

  1. Un groupId : c'est l'identifiant de l'entité (entreprise, association, ...) propriétaire du projet. Ce sont souvent les 2 ou 3 premiers niveaux des packages Java.
    Notre groupId sera ici fr.univtours.polytech.
  2. Un artifactId : c'est l'identifiant du projet. C'est souvent le niveau suivant des packages de l'application. C'est le nom du projet dans eclipse.
    Notre artifactId sera tpjunit5.
  3. Un numéro de version. Une version en cours de développement est suffixée par -SNAPSHOT. Ce sont des versions intermédiaires de travail en local.
    Le numéro de version par défaut à la cration d'un projet Maven est 0.0.1-SNAPSHOT.

À la création d'un projet Maven, un fichier 📄pom.xml est créé. C'est ici que nous allons pouvoir tout paramétrer, notamment l'ajout des dépendances.

L'arborescence d'un projet Maven

Voici l'arborescence d'un projet Maven :

ProjetMaven/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── ici, il y a les packages (qui sont des dossiers) et les classes Java.
│   │   └── resources/
│   │       └── ici, il y a les les fichiers .properties, .xml ...
│   ├── test/
│   │   ├── java/
│   │   │   └── ici, il y a les packages et les classes Java pour les tests unitaires.
│   │   └── resources/
│   │       └── ici, il y a les fichiers .properties, .xml ... pour les tests unitaires.
│   └── target/
│       └── ici, il y a les classes compilées et les ressources.
└── pom.xml
    └── C'est le fichier qui permet de configurer la gestion du projet.

Cela permet d'avoir une classe et la classe de test correspondante dans le même package, mais stockées dans deux endroits différents dans l'application. La première est dans le dossier 📂main, alors que la seconde est dans 📂test.

À la création du projet, le 📄pom.xml contient uniquement :

📄pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.univtours.polytech</groupId>
    <artifactId>tpjunit5</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</project>

Par défaut, la version du compilateur Java utilisée par Maven est la 1.5. Comme nous souhaitons utiliser la 1.8, il faut l'indiquer. Pour cela, il faut ajouter une balise <properties> (fille de la balise <project>) :

Contenu du 📄pom.xml
<properties>
    <maven.compiler.target>1.8</maven.compiler.target>
    <maven.compiler.source>1.8</maven.compiler.source>
</properties>

La balise <maven.compiler.source> permet de préciser la version de Java avec laquelle le code source est compatible. La balise <maven.compiler.target> permet de préciser la version de Java qui sera utilisée pour générer le bytecode.

On peut maintenant ajouter les dépendances au projet, c'est-à-dire JUnit. On utilise pour cela une balise <dependencies> (fille de la balise <project>), contenant autant de <dependency> que souhaité. Chaque dépendance est identifié par le groupId, l'artifactId et la version. Il faut également ajouter une 4ème information, qui est la portée.

La portée d'un module avec maven
  • compile : la dépendance est utilisable par toutes les phases et à l'exécution. C'est la portée par défaut
  • provided : la dépendance est utilisée pour la compilation mais elle ne sera pas déployée car elle est considérée comme étant fournie par l'environnement d'exécution. C'est par exemple le cas des API fournies par un serveur d'applications
  • runtime : la dépendance n'est pas utile pour la compilation mais elle est nécessaire à l'exécution. C'est par exemple le cas des pilotes JDBC (pour la connexion à une base de données).
  • test : la dépendance n'est utilisée que lors de la compilation et de l'exécution des tests. C'est le cas ici, pour JUnit.
Ajout de dependencies

Pour ajouter des dépendances, on peut utiliser le repository de maven. Pour cela, on recherche sur https://mvnrepository.com/ le module qui nous interesse.

Par exemple, en cherchant junit et en sélectionnant le deuxième résultat (qui correspond à JUnit4), comme nous l'avons fait plus tôt, puis en sélectionnant la dernière version, il suffit de copier le code indiqué et de le coller dans le 📄pom.xml à l'intérieur de la balise <dependencies>, c'est-à-dire :

Contenu du 📄pom.xml
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
</dependency>
JUnit5

Pour utiliser JUnit5, il faut ajouter deux dépendances : junit-jupiter-engine et junit-platform-runner.

Finalement, le 📄pom.xml ressemble à cela :

📄pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>fr.univtours.polytech</groupId>
    <artifactId>tpjunit5</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <properties>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.source>1.8</maven.compiler.source>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-engine</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-runner</artifactId>
            <version>1.8.2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
Exercice 4 - Maven & JUnit5

Refaire le projet horloge avec JUnit5. Le code de test sera le même, mais attention, les imports ont changés :

  • L'annotation Test vient maintenant de la classe org.junit.jupiter.api.Test et non plus de org.junit.Test.
  • La méthode assertEquals vient de la classe org.junit.jupiter.api.Assertions et non plus de la classe org.junit.Assert.

L'annotation @Before doit être remplacée par @BeforeEach, et @After doit être remplacée par @AfterEach.

Pour mettre à jour les imports, il suffit de les supprimer, puis de faire CtrlShiftO (dans eclipse), et de sélectionner les bonnes classes.