Test unitaire

Série 1 – corrigé

Introduction

Le code du corrigé est disponible sous la forme d'une archive Zip, qui contient également le code de l'énoncé. Les solutions aux différents exercices sont brièvement discutées ci-dessous.

Exercice 1

Notre version du test unitaire pour BoundedIntQueue se trouve répartie dans deux classes :

BoundedIntQueueTest
Cette classe contient la totalité des tests pour les méthodes de l'interface BoundedIntQueue. Étant donné que plusieurs mises en œuvre de cette interface doivent être testées, BoundedIntQueueTest déclare la méthode abstraite newBoundedIntQueue pour créer une queue bornée. Ensuite, une sous-classe de test concrète existe pour chaque mise en œuvre à tester. Chacune de ces sous-classe ne contient rien d'autre qu'une version concrète de la méthode newBoundedIntQueue, qui fait appel au bon constructeur.
BoundedIntQueueBuggyTest
Cette classe contient justement la première de ces classe concrètes de test. Sa méthode newBoundedIntQueue appelle le constructeur de BoundedIntQueueBuggy.

En exécutant les tests de BoundedIntQueueBuggyTest, hérités de BoundedIntQueueTest, on constate que tous sauf un échouent. A ce stade, il est difficile de dire exactement où se trouvent les erreurs, car une erreur dans une méthode fondamentale comme le constructeur ou la méthode addLast rend impossible le test d'autres méthodes.

Ce problème est inhérent au test et n'a pas vraiment de solution. En pratique, lorsqu'un test échoue, on essaie de déterminer la cause de cet échec avant de corriger le code fautif et de relancer les tests jusqu'à ce qu'ils s'exécutent tous sans erreur. A ce stade de la série, sans avoir accès au code source de BoundedIntQueueBuggy, cela n'est toutefois pas encore possible.

Exercice 2

Notre corrigé contient les deux dernières mises en œuvre de BoundedIntQueue proposées dans l'énoncé, basées sur un tableau d'entiers de type int[]  :

  • BoundedIntQueueSlow s'assure que l'élément en début de queue se trouve toujours à la position 0 du tableau. Comme dit dans l'énoncé, cela rend la méthode removeFirst coûteuse, car elle doit décaler tous les éléments de la queue après suppression. Toutefois, cette mise en œuvre est facile à comprendre.
  • BoundedIntQueueFast tolère quant à elle que l'élément en début de queue soit à un index quelconque du tableau. Sa position est mémorisée dans le champ headPos. Cette technique de mise en œuvre revient à considérer que le tableau contenant les éléments (contents dans notre code) est circulaire plutôt que linéaire.

A chacune de ces deux classes correspond une classe de test, nommées respectivement BoundedIntQueueSlowTest et BoundedIntQueueFastTest.

Il peut être utile de placer dans chacune des deux mises en œuvre des queues bornées des assertions vérifiant certaines de leurs propriétés. Une première propriété qui doit toujours être vraie est que la taille d'une queue bornée est comprise entre 0 et sa capacité. Dans la version rapide de la queue, on sait de plus que la position de l'élément contenant le début de la queue (headPos) doit lui aussi toujours être dans le même intervalle.

Ces deux assertions doivent être vérifiées chaque fois qu'elles sont susceptibles de changer. Comme la capacité d'une queue ne peut changer, il faut les vérifier chaque fois que le champ size (respectivement headPos) change.

Exercice 3

Une fois l'une ou l'autre de ces mises en œuvre écrite et testée, on peut l'utiliser pour exécuter le programme contenu dans GetSecretURL.java. Celui-ci affiche alors le message suivant :

Téléchargez le code source à cette adresse :
https://cs108.epfl.ch/+/2jv41n/BoundedIntQueueBuggy.java

Après téléchargement du fichier référencé, on peut constater — et corriger petit à petit — les erreurs suivantes :

  • le constructeur alloue un tableau trop grand et initialise la taille à 1 plutôt qu'à 0,
  • addLast et removeFirst vérifient trop tard si la queue est pleine ou vide, et lèvent la mauvaise exception.