Objectifs
- Expérimenter l'injection de dépendances
- Expérimenter les mock objects
L'objectif de cette démonstration est d'approfondir l'expérimentation sur les tests unitaires. Comme vous l'avez vu en classe, un bon test unitaire ne doit pas nécessiter des ressources externes. Pour tester des fonctionnalités qui font des accès de ce genre, il faut utiliser des Mock objects.
Commencez par récupérer le projet suivant : INF2015-MOCK
Nous voulons tester la méthode envoyerCourrielMembres de la classe Cours. Cette méthode envoi un courriel à tous les membres du cours. Cependant, cette méthode envoi réellement un courriel aux membres du cours!! L'envoi de courriel implique l'utilisation d'un environnement et un accès à des ressources externes, nous voulons donc éviter d'envoyer des courriels, mais nous voulons quand même pouvoir tester la méthode envoyerCourrielMembres.
Comme nous voudrons "mocker" la classe MailSender, nous devons extraire cette composante de la classe Cours. Au lieu que l'objet Cours instancie à l'interne un MailSender, nous allons lui passer au constructeur un objet MailSender qu'il utilisera par la suite. C'est le principe de l'injection de dépendance.
- Modifier le constructeur pour qu'il accepte un 3e paramètre de type MailSender.
- Modifier le code du constructeur pour qu'on assigne à la variable interne mailSender l'objet MailSender passé en paramètre.
Nous venons de créer une injection de dépendance pour la classe Cours.
- Créez une classe qui hérite de la classe MailSender
- Comme on veut simuler l'envoi de courriel, nous devrons stoquer d'une certaine façon les courriels "envoyés"
- Créez une variable dans votre mock qui stoque les courriels envoyés.
- Vous pouvez vous y aider en créant une classe Courriel avec laquelle vous instancierez les courriels et vous les stockerez dans la collection de courriel.
Le but de cette manipulation est de pouvoir créer des bons tests unitaires sur la fonction envoyerCourrielMembres.
- Creez quelques tests sur la fonction envoyerCourrielMembres en utilisant l'objet Mock créé précédemment.
- Exemple de test : ajouter quelques membres au cours et vérifier que le mock a envoyé le bon nombre de courriel.
Il est possible que la classe que l'on veut mocker ne nous permette pas de l'instancier sans faire un accès à des données. C'est le cas pour la classe FileWriter. En effet, comme le FileWriter crée impérativement un fichier dans chacun de ses constructeurs, il faut contourner ça en l'englobant dans un wrapper.
Remarque : Le FileWriterWrapper prend un FileWriter en paramètre et appelle la fonction Write du FileWriter lorsqu'on apelle la fonction Write du FileWriterWrapper.
- Modifiez la classe Rapport pour lui injecter un FileWriterWrapper, comme pour l'exercice 1
- Examinez la classe FileWriterWrapper et créez un Mock object qui hérite du FileWriterWrapper
- Votre mock doit redéfinir la méthode write.
- Si l'on redéfinit la méthode write, la classe parente n'utilisera pas le FileWriter interne. On peut donc passer un FileWriter nul lors de l'appel au constructeur de la classe parent.
- Comme on veut garder traces de ce que le mock va écrire, on peut stoquer ce qu'il écrira dans un string que l'on gardera dans le mock.
- Nous voulons tester la fonction genererRapport de la classe Rapport. Comme vous pouvez le voir, nous avons déjà injecter la dépendance du FileWriterWrapper dans la classe Rapport. Il ne vous reste qu'à rédiger quelques tests sur la fonction en utilisant le mock précédemment créé.