Test de logiciel – TD 2
Transcription
Test de logiciel – TD 2
Université d’Evry Val d’Essonne M1 MIAGE Test de logiciel – TD 2 L’objectif de cette séance de travaux dirigés est de réaliser un développement itératif dirigé par les tests en utilisant les outils JUnit et Mockito. L’application que nous allons développer et tester est une application ferroviaire où nous devons gérer le franchissement de passages à niveau par des trains. Cette application contiendra des objets tels que de trains, des rails, des passages à niveaux et des contrôleurs. La finalité est de réaliser le scénario suivant où 2 trains vont se croiser sur des voies parallèles composées de rails (voir la configuration ci-dessous) : 1. Démarrer les trains 2 et 1 ; 2. Faites avancer le train 2 puis le train 1 successivement 10 fois ; 3. Le train 2 doit passer le passage à niveau avant le train 1 ; 4. A la fin les 2 trains doivent être arrêtes et on vérifiera qu’ils ont bien parcourus 10 tronçons de rails ; 5. On vérifiera aussi que la barrière des passages à niveau s’est bien baissée puis relevée lors du passage des trains. Il y aura un passage à niveau pour chacune des voies. Ce scénario sera votre test de recette (donc un test système) permettant de valider votre implémentation. Chaque exercice correspond globalement à l’exécution d’une itération. Tous les tests joués à une itération doivent être rejoués à l’itération suivante pour assurer la non régression du code. Si jamais des tests ne passent plus (compilation, échec ou erreur1), il faut en étudier les raisons et : - Modifier le code testé jusqu’à ce que le test repasse car le résultat attendu du test doit toujours être conforme aux spécifications ; Modifier le code du test car la syntaxe du code appelé a évolué, alors que la spécification reste identique ; Supprimer le test car il n’a plus de sens car la spécification a été remise en cause. Remarque : Pour chaque exercice, on mettra les sources dans un package exN, avec N le numéro de l’exercice, et les tests dans le package exN.test. Exercice 1 Lors de la première itération de notre développement, nous avons la responsabilité de développer le composant correspondant au train. Ce composant respecte la description qui suit. Un train dispose des opérations publiques (en plus du (ou des) constructeur(s)) suivantes : démarrer, avancer, arrêter, distanceParcourue, getRail et vérifie les spécifications données ci-dessous : 1 Un test est en échec lorsque le résultat n’est pas conforme à la prédiction de l’oracle ; un test est en erreur quand son exécution s’arrête pour une raison non prévue par le développeur. Université d’Evry Val d’Essonne M1 MIAGE 1. A la création d’un train, une instance de rail lui est injectée2 ; 2. Pour simplifier le problème la longueur d’un train est supposée inférieure à celle d’un rail et sa progression se fait de manière discrète : à un instant le train est sur un rail, à l’instant suivant il est sur le rail d’après ; il n’est jamais sur 2 rails à la fois. 3. Le train stocke le nombre de rails parcourus depuis le dernier démarrage ; 4. Un appel à l’opération démarrer est nécessaire avant de vouloir faire avancer le train ; 5. Si l’on appelle avancer sans avoir démarré le train, une exception de type RuntimeException est propagée ; 6. Lorsque l’on fait avancer le train il se déplace du rail courant vers le rail suivant (qui devient alors le rail courant pour le train) ; 7. On ne peut pas démarrer un train sans l’avoir arrêté au préalable. 8. lorsque l’on arrête le train, il n’est alors plus possible de refaire avancer le train sans avoir au préalable rappelé l’opération démarrer (une exception RuntimeException levée); 9. L’arrêt n’est pas immédiat, il lui faut deux rails pour s’arrêter. Dans le cas où le train n’a pas assez de rails devant lui pour s’arrêter, une exception de type RuntimeException est propagée. De même si un de ces 2 rails est occupé, l’exception est levée ; 10. Si jamais au moment où le train avance, le rail suivant est occupé une exception de type RuntimeException est propagée. Dans pareil cas, l’accident est inévitable, te train ayant besoin de deux rails pour s’arrêter ; Le train collaborant/utilisant des objets de type Rail, il est nécessaire de connaître la spécification de la classe Rail qui est la suivante : - 1. 2. 3. 4. La classe Rail dispose de l’opération suivant() qui retourne un rail si un rail suivant existe, sinon une exception de type RuntimeException est propagée. L’opération setSuivant(…) met à jour le rail suivant. Elle dispose aussi d’une opération estOccupé() qui indique si un train est sur ce rail (true) ou non (false) et d’une opération setOccupé(Boolean b) qui permet d’indiquer au rail qu’il est occupé ou non. Définissez les interfaces que le train et le rail devront vérifier. Appelez les respectivement ITrain et IRail. Ces interfaces sont primordiales pour bien travailler avec les doublures (mocks). Ecrivez le squelette de la classe concrète Train vide où les opérations ne font rien. La classe Train implémentera l’interface ITrain. Le constructeur du train prendra un rail en paramètre. Ecrivez la classe de test JUnit qui servira à tester le comportement de la classe Train par rapport aux spécifications données ci-dessus. a. Attention, vous devez effectuer ces tests sans avoir le code de la classe Rail. Il vous faut donc créer une doublure de rail qui vérifiera la spécification indiquée. Utilisez pour cela la bibliothèque Mockito ; b. Afin de réaliser vos tests, créez dans la méthode setUp de votre classe de test un train et un circuit composé de doublures de rails. Lancez vos tests puis complétez le code de la classe Train jusqu’à ce qu’ils passent tous avec succès. Attention vos tests doivent permettre de valider l’ensemble des 10 points données dans la spécification informelle. Exercice 2 Nous avons maintenant à coder la classe Rail. 1. 2. Codez et testez la classe Rail de manière unitaire (comme effectué à l’exercice 1 pour la classe Train). Mettez à jour votre classe de test de la classe Train qui testera l’utilisation de vrais rails par la classe Train à la place des doublures. 2 En d’autres termes, une instance de rail est passée en argument du constructeur de la classe Train. Cette instance sera le rail sur lequel sera « posé » le train à sa création. Université d’Evry Val d’Essonne M1 MIAGE Exercice 3 Nous prenons maintenant en compte les passages à niveaux pour gérer le croisement entre les voies de chemins de fer et des routes. Ceci va nécessiter l’introduction de nouvelles classes. Tout d’abord, de nouvelles classes PassageANiveaux et Controleur vont être ajoutées et différents types de rails vont être distingués : des rails normaux, des rails de passage à niveaux (au croisement avec les routes) et des rails d’avant passage à niveaux. Ces dernières signalent au train qu’ils se trouvent à une certaine distance du passage à niveau. Ceci nous donne les spécifications suivantes pour les différents éléments : - La classe Contrôleur o Elle déclenche la fermeture et l’ouverture de plusieurs passages à niveaux ; o Si on lui demande d’ouvrir ou fermer un passage à niveaux dont elle n’est pas responsable, une exception de type RuntimeException est propagée ; o Elle connaît un ensemble de passage à niveaux. - La classe PassageANiveaux fournit une opération de fermeture et d’ouverture de la barrière (pour les voitures). o Elle connaît le contrôleur associé ; o Lorsque l’on crée un passage à niveau, celui s’ajoute directement dans la liste des passages à niveaux contrôlés par le contrôleur associé ; o L’ouverture et la fermeture sont instantanées. - La classe RailPassageANiveaux correspond à la portion de rails où est situé le passage à niveau o Quand un train est sur un tel rail, le passage à niveau correspondant doit être fermé, s’il est ouvert un message d’alerte est émis (sortie texte) ; o Quant le train quitte ce rail, il prévient le contrôleur pour lui demander l’ouverture du passage à niveau. La classe RailAvantPassageANiveaux permet d’indiquer au contrôleur qu’un train va arriver à un passage à niveau : o Quand un train quitte un rail avant passage à niveau, il demande au contrôleur la fermeture du passage à niveau correspondant ; o On dispose toujours de 2 rails normaux entre un rail avant passage à niveau et un rail de passage à niveau. En effet, même si le train s’arrête après le rail avant passage à niveau, son arrêt nécessitant 2 rails, il arrivera nécessairement sur le passage à niveau. Pour un passage à niveau donné, on doit donc avoir 2 rails d’écart entre un rail d’avant PAN et le rail PAN. - - Université d’Evry Val d’Essonne M1 MIAGE Vous devez développer l’ensemble de ces nouvelles classes sans avoir connaissance de la classe Train, Pour réaliser vos tests unitaires, vous utiliserez donc des doublures de trains. Notez que la classe Rail a disparu au profit d’une classe abstraite et de 3 classes concrètes. Continuez à vérifiez vos tests pour ces différentes classes. Exercice 4 Maintenant intégrez l’ensemble de vos développements et réalisez le scénario donné en préambule. Ajoutez le à vos suites de test.