Participer au site avec un Tip
Rechercher
 

Améliorations / Corrections

Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.

Emplacement :

Description des améliorations :

Mise en oeuvre de tests unitaires avec JUnit 3.x

Les tests unitaires JUnit 4.x



Accès rapide :
Création d'un projet Eclipse avec le support JUnit 3.x
Les conventions de codage d'une classe de test JUnit 3
Lancer vos tests JUnit
Tester un déclenchement d'exceptions
Les méthodes setUp et tearDown
Bonnes pratiques de développement JUnit

il existe plusieurs versions de JUnit et notamment JUnit 3.x, JUnit 4.x et JUnit 5.x. Entre ces trois branches de versions, il y a eut rupture de compatibilité. Mais comme ces trois versions sont encore beaucoup utilisées au gré des divers projets existants, j'ai fait le choix de vous présenter les trois approches. Bien entendu, si vous êtes nouveau venus dans l'univers Java et si vous n'avez pas d'antériorité en termes de version du JUnit utilisée, je vous propose de passer directement à l'étude de JUnit 5.x.

Les différentes versions 3.x de JUnit ont été écrites à une époque reculée de Java. A cette époque la notion d'annotation n'était pas encore présente dans le langage. Du coup JUnit 3.x utilise des conventions de nommage pour les méthodes de tests que vous allez développer. Si vous respectez les conventions que je vais vous présenter tout se passera bien. Dans le cas contraire, tant pis pour vous ! ;-)

vous l'avez certainement compris, les versions 4.x et 5.x de JUnit ont abandonné ces conventions de nommage au profit des annotations Java. Nous y reviendrons dans les prochains chapitres.

Création d'un projet Eclipse avec le support JUnit 3.x

Dans la suite de ce document, nous allons chercher à tester le code développé durant le chapitre sur l'introduction à la programmation orientée objet. Ce code proposait une simple classe de manipulation de nombre rationnels (de fractions, si vous préférez).

oui je sais, ce n'est pas un vrai composant logiciel comme suggéré dans le chapitre précédent, mais je préfère débuter par un exemple relativement simple.

Nous allons tester ce code en exploitant l'intégration de JUnit au sein d'Eclipse. Donc commencez par créer un nouveau projet : vous pouvez l'appeler Rational. Copiez/collez-y le code de la classe Rational à partir du lien ci-dessus.

Il faut comprendre que mélanger les codes applicatifs et les codes de tests, n'est pas forcément une bonne chose. Eclipse propose une fonctionnalité qui va nous aider à éviter cela : la notion de « Source Folder ». Un tel dossier contient, comme son nom l'indique, des codes sources et force leur compilation. Clairement, le répertoire src est un dossier de cette nature. Pour créer un dossier de codes sources dans votre projet, cliquez avec le bouton droit de la souris sur le projet puis sélectionnez « New / Source Folder ». Appelez ce dossier test

si vous sélectionnez « New / Folder » à la place de « New / Source Folder », vous aurez créé un simple dossier. Oui vous pourrez y mettre des fichiers Java, mais ils ne seront pas compilés.

Voici à quoi doit ressembler votre projet à ce stade.

Création d'un source folder pour nos tests

Il faut maintenant ajouter une classe de test. Pour ce faire, cliquez avec le bouton droit de la souris sur le dossier test et sélectionnez-y l'assistant « New / JUnit Test Case », comme le montre la capture d'écran suivante.

Ajout d'une classe de test

Une nouvelle boîte de dialogue doit apparaître. Notez bien qu'en haut de la fenêtre, vous pouvez choisir la version de JUnit à utiliser. Veuillez cocher la case « New JUnit 3 test ». Veuillez ensuite remplir le champ « Package » avec la valeur fr.koor.poo ainsi que le champ « Name » avec la valeur RationalTest. Voici une capture d'écran de cette boîte de dialogue.

Ajout d'une classe de test et choix de la version de JUnit

Comme c'est la première fois qu'on ajoute une classe de test à ce projet, la librairie JUnit n'y est pas encore présente. Eclipse détecte cette situation et vous propose d'ajouter automatiquement la librairie au ClassPath. Accepter, bien entendu, cette proposition.

Ajout de JUnit dans le classpath

Arrivé à ce stade, voici à quoi doit ressembler votre projet.

Ajout d'une classe de test au projet Eclipse.

Les conventions de codage d'une classe de test JUnit 3

La première règle est assez simple : toute classe de test doit hériter directement ou indirectement de la classe junit.framework.TestCase. Vous ne pouvez donc pas hériter d'une autre classe qui ne soit pas compatible avec TestCase !

Ensuite, vous allez rajouter autant de méthodes que de tests à effectuer. Il faut impérativement que vos méthodes de test aient un nom qui commence par les quatre lettres test. De plus, il faut impérativement que ces méthodes soient publiques, qu'elles n'aient pas de valeur de retour (void) et qu'elles n'acceptent aucun paramètre. Sans quoi, les méthodes ne respectant pas ces règles ne seront pas prises en compte par JUnit.

privilégiez des tests simples. Si vous avez deux choses à vérifier, définissez deux méthodes de tests chacune ne vérifiant que l'un des deux aspects.

Voici un premier exemple de test qui va vérifier si l'addition de deux nombres rationnels se passe bien.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
package fr.koor.poo;

import junit.framework.TestCase;

public class RationalTest extends TestCase {

    // La méthode de test commence bien par le préfixe test.
    public void testAddition() {
        
        // On prépare le scénario de test
        Rational r1 = new Rational( 1, 3);
        Rational r2 = new Rational( 2, 1);
        Rational result = r1.add( r2 );
        
        // On vérifie les résultats
        assertEquals( 7 /* Valeur attendue */, result.getNumerator() /* Valeur constatée */);
        assertEquals( 3 /* Valeur attendue */, result.getDenominator() /* Valeur constatée */);
        
    }
    
}
Un premier test JUnit pour vérifier l'addition de deux nombres rationnels

Les méthodes commençant par assert sont héritées de la classe TestCase. Elles permettent de vérifier vos résultats. Si l'assertion est vraie, le test se poursuit normalement est aucun message d'erreur sera produit. Dans le cas contraire, ces méthodes déclenchent des exceptions permettant d'interrompre le test et de le passer dans l'état échoué.

Vous pouvez y ajouter un second test pour vérifier si la simplification de fraction se passe correctement. Voici un exemple de code pour ce second test.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
package fr.koor.poo;

import junit.framework.TestCase;

public class RationalTest extends TestCase {

    // La méthode de test commence bien par le préfixe test.
    public void testAddition() {
        
        // On prépare le scénario de test
        Rational r1 = new Rational( 1, 3);
        Rational r2 = new Rational( 2, 1);
        Rational result = r1.add( r2 );
        
        // On vérifie les résultats
        assertEquals( 7 /* Valeur attendue */, result.getNumerator() /* Valeur constatée */);
        assertEquals( 3 /* Valeur attendue */, result.getDenominator() /* Valeur constatée */);
        
    }
    
    // La seconde méthode de test
    public void testSimplify() {
    
        // On prépare le scénario de test
        Rational r = new Rational( 5*7*11*13, 11*13*17 );
        r.simplify();

        // On vérifie les résultats
        assertEquals( 35, r.getNumerator() );
        assertEquals( 17, r.getDenominator() );
    
    }
    
}
Un second test JUnit pour vérifier la simplification de fraction

Lancer vos tests JUnit

Pour lancer le jeu de tests, veuillez cliquer avec le bouton droit de la souris sur le nom de la classe et lancez l'assistant « Run As / JUnit Test ». Les résultats des tests sont affichés dans la vue « JUnit » comme le montre la capture d'écran suivante.

Lancement de votre jeu de tests dans JUnit.

La vue « JUnit » affiche donc les résultats. Pour chaque test lancé, vous avez l'information sur le temps qu'il a pris durant son exécution. On y voit aussi que nous avons démarré deux tests et que nous avons tous ces tests en succès et aucun en échec. En conséquence, on y voit la barre de statut complétement verte. Dans le cas contraire elle aurait été rouge. Voici un exemple de détection d'un test en échec (j'ai modifié le code de la méthode add pour que le calcul se passe mal).

Détection d'un problème par JUnit.

En fait, les possibilités de démarrage de vos tests sont plus subtiles qu'il n'y parait. Vous pouvez choisir « la quantité » de tests à exécuter en cliquant à différents endroits de l'interface graphique d'Eclipse.

Notez aussi que, si vous avez déjà lancé un ensemble de tests et que vous souhaitez relancer cet ensemble, vous pouvez cliquer sur le bouton « Rerun Test », comme le montre la capture d'écran ci-dessous.

Relancer un jeu de tests.

Tester un déclenchement d'exceptions

Tester une application ne veut pas dire tester que ce qui doit marcher. Il faut aussi vérifier que tous les cas d'erreur connus sont bien détectés. Dans notre cas, il n'est normalement pas possible de créer une fraction avec la valeur 0 en dénominateur. Il faut donc tester qu'on détecte bien ce type de problème.

Le souci est que si une exception remonte à JUnit, le scénario de test sera considéré comme étant échoué. Comment inverser les choses ? En fait, c'est assez simple : un banal bloc try / catch couplé à un appel à la méthode fail permet de gérer la difficulté. Voici un exemple de code pour vérifier ce point.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
package fr.koor.poo;

import junit.framework.TestCase;

public class RationalTest extends TestCase {

    // Les autres méthodes de tests
    // ...
    
    // On teste un déclenchement d'exception.
    public void testBadDenominator() {
        try {
            new Rational( 1, 0 );
            // Si on arrive ici, ce n'est pas normal => on plante le scénario
            fail( "Exception is needed" );
        } catch( RuntimeException exception ) {
            // Yes ! On a capturé l'exception, le test est donc Ok.
            // On a donc rien à faire de plus.
        }
    }

}
Tester le déclenchement d'une exception

Et voici les résultats produits par notre nouveau jeu de tests.

On test un déclechement d'exception.

Les méthodes setUp et tearDown

Pour clore ce chapitre, je voudrais porter mon attention sur deux méthodes complémentaires : les méthodes setUp et tearDown.

La méthode setUp, si elle est définie, est invoquée avant l'exécution de chaque méthode de test. Dans notre classe de test, nous avons trois méthodes préfixées par test, la méthode setUp sera donc lancée trois fois. Par exemple, si chacun de vos tests nécessite une connexion à une base de données, il ne faut pas que l'exécution du test précédent mette en péril l'exécution de la méthode de test courante, par exemple avec des transactions en cours ou encore une fermeture de connexion à la base. Le mieux est donc de réouvrir une connexion propre avant chaque exécution de test.

De manière symétrique, il existe une méthode permettant de nettoyer un éventuel contexte : la méthode tearDown. Elle sera exécutée à la fin de chaque méthode de test et dans notre cas, trois fois. Si l'on reprend l'exemple de l'utilisation d'une connexion à une base de données pour chacun de vos tests, dans ce cas, vous pouvez fermer chaque connexion à la fin du test via la méthode tearDown.

Outre le respect des noms de ces deux méthodes, elles doivent aussi être publiques, ne rien renvoyer et ne pas accépter de paramètre. Si vous ne respectez pas ces règles, elles seront purement et simplement ignorées.

Lors de la création d'une nouvelle classe de test, vous pouvez demander à Eclipse de produire ces méthodes en cochant les cases associées, comme le montre la capture d'écran suivante.

Exemple de génération des méthodes setUp et tearDown par Eclipse.

Voici un exemple basique de définition de ces deux méthodes : l'objectif est simplement de vous montrer qu'elles déclenchent avant est après chaque appel à une méthode de test.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
package fr.koor.poo;

import junit.framework.TestCase;

public class SetUpTearDownTest extends TestCase {

    protected void setUp() throws Exception {
        System.out.println( "Avant chaque méthode de test" );
    }
    
    public void testMethod1() {
        System.out.println( "Test 1" );
    }

    public void testMethod2() {
        System.out.println( "Test 2" );
    }

    public void testMethod3() {
        System.out.println( "Test 3" );
    }

    protected void tearDown() throws Exception {
        System.out.println( "Après chaque méthode de test");
    }

}
Exemple de définition des méthodes setUp et tearDown

Et voici les résultats qui seront affichés dans la console Eclipse suite à l'exécution de vos tests.

Exemple d'exécution des méthodes setUp et tearDown par Eclipse.

Bonnes pratiques de développement JUnit



Les tests unitaires JUnit 4.x