12.07.2013 Views

Génie Logiciel Avancé TP - Test unitaire avec JUnit - LRI

Génie Logiciel Avancé TP - Test unitaire avec JUnit - LRI

Génie Logiciel Avancé TP - Test unitaire avec JUnit - LRI

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Prof. Burkhart Wolff<br />

wolff@lri.fr<br />

<strong>TP</strong> - <strong>Test</strong> <strong>unitaire</strong> <strong>avec</strong> <strong>JUnit</strong><br />

Semaine du 10/10/2011<br />

<strong>Génie</strong> <strong>Logiciel</strong> <strong>Avancé</strong><br />

Année 2011-2012<br />

Delphine Longuet, Lina Ye<br />

longuet@lri.fr, lina.ye@lri.fr<br />

L’objectif de ce <strong>TP</strong> est d’écrire et d’exécuter des tests <strong>avec</strong> <strong>JUnit</strong> pour un ensemble de<br />

classes Java implantant un agenda. À partir de la spécification informelle donnée, vous devez<br />

écrire un ensemble de classes <strong>JUnit</strong> de façon à pouvoir tester des implantations de l’agenda en<br />

boîte noire. Les squelettes des classes de test ainsi que les implantations à tester sont disponibles<br />

à l’adresse http://www.lri.fr/~longuet/Enseignements/11-12/Agenda.tar.gz.<br />

Spécification de l’agenda On considère la classe Agenda dont chaque instance représente<br />

l’emploi du temps d’une personne. Un emploi du temps est un ensemble d’événements dont<br />

chacun est identifié par un nom, une date de début et une date de fin. Un événement est une<br />

instance de la classe Evenement. Le nom d’un événement ne doit pas être vide. La durée d’un<br />

événement s’étend entre sa date de début incluse et sa date de fin excluse. Un événement ne<br />

peut pas avoir une durée nulle, et sa date de début doit précéder sa date de fin. La création<br />

d’un événement qui ne respecte pas ces conditions lève l’exception ErreurEvenement.<br />

On peut ajouter et supprimer un événement d’un agenda, chercher quel événement a lieu<br />

à une date donnée, chercher par son nom si un événement est présent dans l’agenda, connaître<br />

les dates de début et de fin d’un événement prévu.<br />

Les événements d’un agenda doivent tous avoir des noms différents et ne doivent pas se<br />

chevaucher. Un événement ne peut donc être ajouté à un agenda que si un événement de même<br />

nom n’existe pas déjà et s’il n’est en conflit <strong>avec</strong> aucun des événements déjà présents dans<br />

l’agenda. Ainsi, à une date donnée, un agenda contient au plus un événement. L’ajout d’un<br />

événement renvoie un booléen permettant de savoir si l’ajout a été effectué. Il en est de même<br />

pour la suppression d’un événement.<br />

La recherche d’un événement à une certaine date renvoie le nom de l’événement prévu s’il<br />

existe, le mot vide sinon. Si on cherche la date de début ou de fin d’un événement qui n’est<br />

pas présent dans l’agenda, l’exception ErreurAgenda est levée.<br />

Une date est en réalité une date du calendrier plus une heure de la journée (sur 24 heures).<br />

C’est une instance d’une classe Date donnée par le jour, le mois, l’année, les heures et les<br />

minutes. Une date doit être postérieure au 1 er janvier 1970, 0h00. La création d’une date<br />

erronée lève l’exception ErreurDate.<br />

Le squelette de la classe Java Agenda est le suivant.<br />

public class Agenda {<br />

public Agenda() { }<br />

public boolean ajouter (Evenement e) { }<br />

public boolean supprimer (String nom) { }<br />

public String chercherEvenement (Date d) { }<br />

public Date dateDebut (String nom) throws ErreurAgenda { }<br />

public Date dateFin (String nom) throws ErreurAgenda { }<br />

public boolean prevu(String nom) { }<br />

}<br />

1


Le constructeur de la classe Date a la forme :<br />

public Date(int jour, int mois, int annee, int heure, int minute)<br />

throws ErreurDate { }<br />

et celui de la classe Evenement a la forme :<br />

public Evenement(String nom, Date debut, Date fin)<br />

throws ErreurEvenement { }<br />

Introduction à <strong>JUnit</strong> <strong>JUnit</strong> est un outil permettant d’écrire et d’exécuter des tests <strong>unitaire</strong>s<br />

sur des programmes Java. Il est intégré à Eclipse mais est égalenemt disponible à l’adresse<br />

http://www.junit.org/.<br />

Les tests en <strong>JUnit</strong> sont regroupés au sein d’une classe Java qui doit hériter de la classe<br />

<strong>Test</strong>Case. Le nom des méthodes de test doit commencer par test. Le corps d’une méthode<br />

de test doit comporter trois parties :<br />

– le préambule, qui permet l’initialisation des objets sur lesquels le test va être exécuté ;<br />

– le corps de test, dans lequel la méthode à tester est appelée sur les objets créés;<br />

– le postambule, qui permet de délivrer le verdict du test (succès ou échec) en vérifiant un<br />

ensemble de propriétés (assertions) sur l’état des objets après le test. Le tableau 1 à la<br />

fin de l’énoncé résume les différentes assertions possibles en <strong>JUnit</strong>.<br />

◮ Sous Eclipse, créez un nouveau projet à partir du répertoire <strong>Test</strong>Agenda fourni. Ajoutez<br />

<strong>JUnit</strong>3 au classpath : clic droit sur le projet > Build Path > Add Librairies > Junit3. Puis<br />

ajoutez une des implantations de la classeAgenda fournies : clic droit sur le projet > Build Path<br />

> Add External Archives, puis ajouter le fichier Agenda4.jar du répertoire Implantations,<br />

par exemple.<br />

◮ Ouvrez la classe <strong>Test</strong>s donnée en exemple. Elle contient quatre méthodes de test :<br />

1. La méthode testDate31Janvier vérifie que la création de la date du 31 janvier 2011,<br />

22h30 est possible (et donc que le mois de janvier a bien 31 jours). Comme la création de<br />

cette instance de Date ne doit pas lever d’exception, le test doit échouer si une exception<br />

est levée. On rattrape alors l’exception et on force l’échec du test <strong>avec</strong> la méthodefail().<br />

2. La méthodetestEvenementSansNom vérifie qu’il n’est pas possible de créer un événement<br />

dont le nom est vide. On fait échouer le test si aucune exception n’est levée, et également<br />

si l’exception levée n’est pas celle attendue.<br />

3. La méthode testAgendaAjouterEvenementSimple vérifie qu’il est possible d’ajouter un<br />

événement à un agenda vide. On vérifie que l’événement a bien été ajouté à l’agenda,<br />

c’est-à-dire qu’il est bien prévu, que ses dates de début et de fin sont correctes, et qu’on<br />

le trouve lorsqu’on cherche quel événement a lieu à une date comprise entre son début<br />

et sa fin. On force le test à échouer si une exception est levée au cours de l’exécution.<br />

4. La méthode testAgendaDebutAbsent vérifie que la recherche du début d’un événement<br />

qui n’existe pas dans l’agenda lève l’exception ErreurAgenda et ne modifie pas l’agenda.<br />

Dans ce cas, on fait échouer le test si aucune exception n’est levée ou si l’exception<br />

levée n’est pas correcte. On vérifie que l’agenda n’a pas été modifié en s’assurant que les<br />

événements prévus sont les mêmes et aux mêmes dates.<br />

◮ Pour exécuter ces tests sur une implantation en boîte noire (une archive .jar), il faut ajouter<br />

le fichier au classpath comme vu précédemment. Exécutez ensuite <strong>Test</strong>s en tant que test <strong>JUnit</strong><br />

2


sur l’implantation Agenda4.jar. Le résultat des tests apparaît dans un nouvel onglet : un<br />

test ayant levé une exception non rattrapée est répertorié dans Errors, un test ayant échoué<br />

(AssertionFailedError) est répertorié dans Failures.<br />

Afin de regrouper les tests selon la classe testée, on répartira les tests entre trois classes<br />

<strong>Test</strong>Date, <strong>Test</strong>Evenement et <strong>Test</strong>Agenda. Il est possible de factoriser l’initialisation et la<br />

remise à zéro des objets utilisés dans plusieurs tests en définissant des méthodes appelées<br />

setUp et tearDown, qui seront exécutées respectivement avant et après chaque test.<br />

◮ Ouvrez la classe <strong>Test</strong>Agenda qui illustre l’utilisation de ces méthodes. On remarque qu’on<br />

rattrape également une éventuelle exception dans le corps de la méthode setUp, au cas où<br />

l’initialisation échoue. La méthode suite sert à construire une suite de tests à partir des méthodes<br />

setUp et tearDown et des méthodes de test. Cette suite de test correspond à l’exécution<br />

des méthodes selon l’ordre :<br />

setUp(); test1(); tearDown(); setUp(); test2(); tearDown(); ...<br />

◮ Exécutez ensemble<strong>Test</strong>Date,<strong>Test</strong>Evenement et<strong>Test</strong>Agenda sur l’implantationAgenda4.jar :<br />

clic droit sur le package > Run As > <strong>JUnit</strong> <strong>Test</strong>.<br />

Exercice : écriture et exécution des tests<br />

◮ Complétez les squelettes des trois classes de test fournies en suivant les exemples précédemment<br />

donnés. En particulier, pour chacun des tests, précisez en commentaire l’objectif du<br />

test ainsi que le résultat attendu. Pensez à tester aussi bien les cas qui doivent réussir que<br />

les cas qui doivent lever une exception : l’objectif est de couvrir un maximum de cas. Pensez<br />

également aux cas aux limites.<br />

◮ Dans un fichier texte ou tableau, résumez les résultats des tests sur les 17 implantations<br />

fournies : pour chaque implantation, dites si elle réussit ou échoue aux tests et expliquez les<br />

fautes trouvées. Vous pouvez suivre le modèle suivant :<br />

Implantation Résultats des tests Fautes trouvées<br />

Agenda4 Échec Mauvais nombre de jours au mois de janvier<br />

Méthode Rôle<br />

assertEquals(Object a, Object b) Vérifie que les objets a et b sont égaux<br />

assertSame(Object a, Object b) Vérifie que a et b sont des références vers le même<br />

objet<br />

assertNotSame(Object a, Object b) Vérifie que a et b ne sont pas des références vers<br />

le même objet<br />

assertNull(Object o) Vérifie que l’objet o est null<br />

assertNotNull(Object o) Vérifie que l’objet o n’est pas null<br />

assertTrue(boolean e) Vérifie que l’expression e est vraie<br />

assertFalse(boolean e) Vérifie que l’expression e est fausse<br />

fail() Provoque l’échec du test<br />

Fig. 1 – Méthodes d’assertions en <strong>JUnit</strong><br />

3

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!