TD 3 : JUnit 4

PhilippeCollet

Le retour des bébêtes

  • Créez un nouveau projet dans Eclipse pour ce 3ème TD.
  • Téléchargez l'archive junit4bebetes.zip et recopiez comme il faut les fichiers fournis dans votre projet, puis actualisez le pour qu'ils tiennent compte de ces nouveaux fichiers Java.

Vous êtes toujours face au simulateur de bébêtes, mais sa conception a légèrement changé :

  • La classe principale de l'application s'appele maintenant LanceBebetes. Tout est en Swing et la fenêtre principale est une JFrame et le champ un JPanel. Les tailles sont gérées par setPreferredSize() sur le JPanel et pack() sur la JFrame.
  • L'angle et la longueur de vue sont maintenant placés dans BebeteAbstraite.
  • La vitesse est de type float pour éviter la diminution de la vitesse lors des calculs (troncature en int).
  • La plupart des attributs des bébêtes sont maintenant "protected" et des méthodes getter et setter sont fournies.
  • Des attributs pour gérer la distance minimale entre les bébêtes émergentes sont placés dans... BebeteEmergente.
  • L'action d'une bébête est définie un peu plus précisément :
    • La méthode agit() n'est plus abstraite dans BebeteAbstraite, elle définit une action par défaut, qui consiste à appeler successivement deux autres méthodes (abstraites dans cette classe) : calculeDeplacementAFaire() qui peut modifier la vitesse et la direction suivant où veut aller la bébête, puis effectueDeplacement() qui doit effectuer le déplacement en modifiant x et y en conséquence (ALERT! il est aussi possible que cette dernière méthode modifie la vitesse et la direction, pour modéliser des collisions, des rebonds, etc.).
    • La classe BebeteEmergente fournie est une forme de correction du TD 1. Elle définit notamment les méthodes calculeDeplacementAFaire() et effectueDeplacement(), mais elle redéfinit aussi la méthode agit() pour modifier le comportement en fonction de la distance minimale (ne pas se déplacer si on voit une autre bébête trop près).
  • Vous trouverez aussi une correction du TD 2, dans la classe BebeteAbstraite qui redéfinit la méthode toString() en utilisant la réflexivité. Le champ de bébêtes a aussi été modifié pour répondre au clic souris, chercher la bébête la plus proche et afficher dans une petite fenêtre le résultat de toString().

Ecriture de tests unitaires

On décide de créer une nouvelle bébête, qui se ballade au hasard et qui rebondit sur les bords du champ. Comme vous travaillez presque en eXtreme Programming, votre collègue a déjà implémenté BebeteHasard.java et vous n'avez pas encore écrit les tests (si vous travailliez en eXtreme Progamming, vous auriez écrit les tests d'abord !). On va s'en occuper.

  • Vous pouvez déjà exécuter LanceBebete et regarder le résultat.
  • Votre collègue a déjà implémenté BebeteHasard, et il aussi changé le champ pour créer 10 BebeteHasard.
  • Vous observez qu'il a du mal faire son travail car certaines des bébêtes disparaissent ou ne rebondissent pas très bien...

Réflexion préliminaire

On pourrait très bien se passer du code de BebeteHasard.java pour écrire nos tests, mais on ne peut s'empêcher d'aller jeter un coup d'oeil :

  • La classe BebeteHasard redéfinit bien correctement les deux méthodes pour déterminer l'action.
  • Dans calculeDeplacementAFaire(), elle utilise une variable nbTour pour changer de direction et de vitesse au bout d'un certain nombre de tours.
  • La méthode effectueDeplacement() s'occupe de déplacer x et y, et surtout de faire rebondir la bébête en modifiant aussi la direction. On va commencer par cette méthode !!!

Réfléchissez à quels tests il faudrait mettre en oeuvre (quelles sont les partitions d'équivalence, les valeurs moyennes, les fameuses valeurs aux bornes).

Un premier test

  • Dans l'explorateur de packages, dépliez le menu contextuel sur la classe BebeteHasard, dans le sous-menu New, créez un scénario de test JUnit.
  • Sur le premier panneau, il est possible de choisir la création de tests compatibles avec JUnit 3 ou 4. Dans le cadre de ce TP, nous utiliserons JUnit 4.
  • Vous devez ensuite être face a un assistant de création de test unitaire.
  • Vous remarquez que le champ classe à tester est déjà renseigné. Modifiez plutôt le nom du package pour que ce soit bebete.test .
  • Normalement, les cases correspondant à la génération des méthodes setup() et teardown() sont cochées, sinon cochez les et passez au panneau suivant.
  • Vous pouvez maintenant sélectionner les méthodes à tester. Commencez par cocher la case correspondant à effectueDeplacement et terminez l'assistant.
  • La première fois, un message doit vous indiquer que votre projet ne dispose pas de la bibliothèque JUnit dans le chemin du projet. Il suffit de valider pour que le jar correspondant soit dans les chemins nécessaires pour votre projet (merci Eclipse...).

En cas de problème, jetez un coup d'oeil sur le tutorial de jm doudoux sur JUnit et Eclipse (partie spécifique à JUnit 4 à la fin).

Observez le code produit. Pas mal de choses ont été générées automatiquement :

  • La classe de test, les méthodes setup et teardown ainsi qu'une méthode testEffectueDeplacement qui renvoie par défaut un échec (pour Eclipse 3.2 et versions supérieures) :
    fail("Not yet implemented");
  • Par un clic droit sur cette nouvelle classe de test, exécutez la en tant que test JUnit. Eclipse va la faire exécuter par un TestRunner intégré à l'environnement.
  • Observez le résultat dans les deux panneaux latéraux à gauche : le panneau supérieur résume les tests passés (et permet d'en relancer certains avec des boutons spécialisés), le panneau inférieur donne le détail d'échec d'un test sélectionné.

A présent, il reste a créer effectivement le contexte et le premier test :

  • Réfléchissez à ce dont on a besoin de faire dans le setup pour pouvoir tester unitairement la méthode en question, puis sur ce qu'il faut appeler comme méthode et enfin quoi vérifier (les 3 étapes du test !).

Aide :

  • On n'a pas besoin de faire afficher le champ pour tester que le déplacement est correct. En revanche on a besoin d'un objet champ correctement initialisé
  • Pour démarrer, on peut créer une seule bébête, au milieu du champ, avec une vitesse quelconque, un angle simple (0 par exemple !).
  • Pour la tester, il suffit d'appeler la méthode qui effectue le déplacement (c'est déjà dans le code normalement), puis une ou plusieurs méthodes assertXXX() pour vérifier ce qui est nécessaire (pensez à la complétion automatique pour écrire les assertXXX).
  • Normalement, votre simple test doit passer (sinon c'est votre test qui est faux), car les erreurs sont plutot dans la gestion des rebonds sur les bords...

Le jeu des 3 erreurs

Trouvez les autres tests à écrire et ajoutez des méthodes testXXX() avec des noms significatifs dans le même TestCase. Vous remarquerez que l'environnement exécute automatiquement vos nouvelles méthodes de test (merci la réflexivité).

Aide :

  • Il y a 3 erreurs à trouver dans le code de la méthode
  • Les test aux bornes sont à faire quand une bébête arrive sur un bord (il y en a 4) et qu'il faut bien calculer les valeurs attendues.
  • En haut à gauche du champ, x est à 0, y est à 0. La direction à 0 pointe à droite, elle est censée être dans l'intervalle [0,2PI[, PI/2 pointant vers le bas, PI vers la gauche, et 3PI/2 pointant vers le haut.

Objet Mock / Mockito

Installation

Récupérez le jar de Mockito : http://code.google.com/p/mockito/downloads/detail?name=mockito-all-1.9.5.jar

Placez le dans votre workspace, idéalement dans un répertoire lib indépendant des projets que vous avez créés pour les TPs.

Dans votre projet actuel sous Eclipse, allez dans Project/Properties, puis sélectionnez "JavaBuildPath" à gauche et faites "add external JARs", puis naviguez jusqu'au jar pour qu'il soit ajouté au classpath de compilation et d'exécution.

Tests avec Mock du déplacement de Bebete Hasard

Reprenez les tests précédents et remplacez la création explicite du champ par un object mock de ce champ. Réfléchissez à quelles méthodes vous devez "stubber" au minimum (utilisation de when) pour que vos tests fonctionnent (n'essayez pas de simuler entièrement le champ, juste ce dont vous avez besoin pour effectuer les tests de rebond, tout le principe est la !).

1 Test avec Mock du comportement de Bebete Emergente

Ecrivez un seul test pour vérifier le comportement de base d'une bébête Emergente. Vous devez :

  • avoir un champ
  • avoir une deux bebetes émergentes :
    1. la première est au centre du champ
    2. la seconde est a cote, dans le champ de vision de la première, et possède une direction perpendiculaire à l'autre

Après avoir appelé calculDeplamcementAFaire() sur la première bebete, vous devez vérifier:

  • que sa vitesse est la moyenne (de la sienne et de l'autre)
  • que sa direction est la moyenne des deux angles
  • que les méthodes setDirectionCourante et setVitesseCourante n'ont été appelé qu'une seule fois (sinon, l'algo n'est pas cohérent...).

TIP Vous devez utiliser plusieurs mocks, appliquer des méthodes when, et des méthodes verify. Vous pouvez aussi vous aider des Matchers (voir la mise a jour dans le cours No 3).

TIP Lorsque vous utilisez une méthode verify :

  • Vous pouvez l'appliquer sur n'importe quel objet mock
  • Vous devez explicitement "espionner" un objet normal : Dans le setup du test (et pas dans la méthode de test) appelez directement
    bt= spy(new BebeteEmergente(champ, 320, 240, 0.0F, 10.0F, Color.RED));
Le support de cours a été mis à jour avec une explication sur "spy".

Un autre test

Si vous avez terminé :

  • Ecrivez un nouveau TestCase (et hop l'assistant de création) qui teste la méthode fabriqueBebetes() du champ. Ecrivez un seul test (pas aux bornes), simplement pour vérifier un minimum de choses à la sortie de la fabrique.
  • Exécutez votre test.
  • Essayez de lancer les deux classes de test en passant par le package test dans l'explorateur (merci la réflexivité).

-- PhilippeCollet - 09 Nov 2012

Revision: r1.9 - 09 Nov 2012 - 13:56 - PhilippeCollet
Minfo > GlTD3
Copyright © 1999-2017 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding WIKIDeptinfo? Send feedback