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
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