1 00:00:00,610 --> 00:00:02,670 Bonjour. Dans cette séquence on va voir le framework de 2 00:00:02,870 --> 00:00:06,220 test, SUnit en Pharo, qui permet d'écrire des tests 3 00:00:06,420 --> 00:00:07,960 unitaires comme on va le voir. 4 00:00:09,660 --> 00:00:12,910 Un framework de test sert à supporter le développement agile. 5 00:00:13,880 --> 00:00:15,910 L'idée, c'est de faire du développement incrémental et de 6 00:00:16,110 --> 00:00:19,720 tester régulièrement son code pour voir si quand on l'a 7 00:00:19,920 --> 00:00:22,170 modifié, on n'a pas cassé une propriété ou un invariant 8 00:00:22,370 --> 00:00:25,310 quelque part dans le code. L'idée, c'est d'être préparé au changement. 9 00:00:25,510 --> 00:00:28,720 On écrit des tests et ensuite on modifie son code, puis 10 00:00:28,920 --> 00:00:31,230 on va être capable de réexécuter les tests pour voir si 11 00:00:31,430 --> 00:00:33,500 on n'a pas cassé ou modifié quelque chose qu'il n'aurait pas fallu. 12 00:00:33,900 --> 00:00:36,180 Avoir des tests automatisés c'est extrêmement important 13 00:00:36,450 --> 00:00:38,000 pour supporter ce type de programmation. 14 00:00:38,930 --> 00:00:42,550 Le framework SUnit est un framework spécialisé pour l'écriture 15 00:00:42,750 --> 00:00:44,870 de tests, qui en facilite l'écriture, il est composé de 4 16 00:00:45,070 --> 00:00:46,090 classes donc il est vraiment très simple. 17 00:00:46,610 --> 00:00:48,480 Originellement il a été développé par Kent Beck. 18 00:00:49,210 --> 00:00:52,310 Il a été l'inspiration de nombreux frameworks de tests 19 00:00:52,510 --> 00:00:54,590 dans d'autres langages, comme J-Unit, par exemple. 20 00:00:56,040 --> 00:00:56,800 Qu'est-ce qu'un test ? 21 00:00:57,640 --> 00:01:00,210 Quand on écrit un test on effectue 3 étapes. 22 00:01:00,410 --> 00:01:03,430 Première étape, on met en place un contexte, par exemple 23 00:01:03,630 --> 00:01:04,390 je crée un set vide. 24 00:01:05,130 --> 00:01:10,030 Deuxième étape je crée un stimulus, ici, j'essaie d'insérer 25 00:01:10,510 --> 00:01:14,760 2 fois un élément dans le set que je viens de créer. 26 00:01:15,030 --> 00:01:19,140 Troisième étape, je teste le résultat que j'obtiens, c'est-à-dire 27 00:01:19,340 --> 00:01:22,580 que je m'attends à ce que le set ne contienne qu'un seul 28 00:01:22,780 --> 00:01:24,620 élément, car je vous rappelle un objet set ne peut 29 00:01:24,820 --> 00:01:28,900 contenir qu'une seule fois un élément, il ne peut pas le contenir 2 fois. 30 00:01:29,100 --> 00:01:31,860 Je teste le résultat en espérant que l'invariant n'est pas cassé. 31 00:01:33,310 --> 00:01:34,180 Je vous montre l'exemple. 32 00:01:34,400 --> 00:01:36,700 Pour écrire un test, il faut que j'écrive une sous-classe 33 00:01:36,900 --> 00:01:39,190 de TestCase, en l'occurrence ici je l'appelle SetTestCase. 34 00:01:41,000 --> 00:01:42,030 C'est pour tester les sets. 35 00:01:42,270 --> 00:01:44,110 Je définis une méthode qui s'appelle testAdd. 36 00:01:44,920 --> 00:01:46,610 On verra que toutes les méthodes commencent par test. 37 00:01:47,490 --> 00:01:49,100 Et puis, je mets en place le contexte. 38 00:01:49,300 --> 00:01:51,510 Je crée une instance de la classe set qui est vide. 39 00:01:52,410 --> 00:01:53,170 Je tente 40 00:01:57,690 --> 00:02:01,120 d'ajouter 2 fois cet élément dans mon ensemble, donc 2 41 00:02:01,320 --> 00:02:02,780 fois l'élément 5, ici et ici. 42 00:02:03,000 --> 00:02:05,720 Et in fine, je teste, donc là j'ai un check. 43 00:02:06,350 --> 00:02:11,080 J'utilise la méthode assert pour ça ou je regarde que la 44 00:02:11,280 --> 00:02:14,870 taille de mon set est bien 1, que j'ai bien réussi à 45 00:02:15,070 --> 00:02:16,870 ajouter qu'une seule fois l'élément. 46 00:02:17,070 --> 00:02:21,940 Je peux lancer le test grâce à cette expression 47 00:02:22,470 --> 00:02:26,020 et donc mon test sera vert si l'invariant, si le assert, 48 00:02:26,220 --> 00:02:28,280 si l'expression qui est passée ici est vraie. 49 00:02:29,820 --> 00:02:31,720 Toutes les méthodes qui commencent par la chaîne de 50 00:02:31,920 --> 00:02:35,670 caractères test représentent un test et seront 51 00:02:35,870 --> 00:02:38,090 automatiquement exécutées par l'outil de testRunner. 52 00:02:40,500 --> 00:02:44,040 On verra que tous les résultats, donc toute l'exécution 53 00:02:44,240 --> 00:02:45,530 de la méthode test produit un résultat. 54 00:02:45,760 --> 00:02:49,720 Ces résultats y sont agrégés tous et ils sont agrégés au 55 00:02:49,920 --> 00:02:51,560 sein d'un objet instance de la classe testResult. 56 00:02:54,310 --> 00:02:55,590 Je vous donne un autre exemple. 57 00:02:56,120 --> 00:02:59,080 Dans cet exemple on a bien la méthode de test, son nom 58 00:02:59,280 --> 00:03:02,680 commence par est en minuscule. Donc ici, c'est le nom de 59 00:03:02,880 --> 00:03:04,050 cette méthode, AdjacentRunsWithEqualsAttributAreMerged. 60 00:03:08,300 --> 00:03:11,340 On a le contexte, ici, qui est posé. 61 00:03:11,540 --> 00:03:12,370 On a créé un objet. 62 00:03:13,190 --> 00:03:14,420 Ici, on a un stimuli. 63 00:03:15,000 --> 00:03:19,570 On a tenté d'envoyer le message AddLastTimes à cet objet 64 00:03:19,770 --> 00:03:24,040 3 fois, avec une première fois des paramètres qui sont 65 00:03:24,240 --> 00:03:27,300 ici et une deuxième fois les mêmes paramètres, en 66 00:03:27,500 --> 00:03:30,790 deuxième et troisième fois. On teste, in fine, ici c'est 67 00:03:31,000 --> 00:03:34,040 le check, que cet élément est bien de taille 2. 68 00:03:36,270 --> 00:03:41,000 On n'a pas pu ajouter plusieurs fois le même élément de façon adjacente. 69 00:03:42,230 --> 00:03:44,760 Dans l'exécution d'un test, il y a plusieurs cas de 70 00:03:44,960 --> 00:03:47,430 figure qui peuvent se produire. Il y a un cas de figure 71 00:03:47,630 --> 00:03:49,880 qui correspond à ce qu'on appelle une failure, c'est-à-dire 72 00:03:50,160 --> 00:03:53,110 c'est une des assertions, un invariant qu'on pensait vrai 73 00:03:53,310 --> 00:03:55,480 ou qui devrait être vrai mais qui est faux. 74 00:03:55,900 --> 00:04:00,540 Dans ce cas-là, le test, on dit qu'il contient 75 00:04:00,740 --> 00:04:03,520 une failure. C'est un problème qui est anticipé. 76 00:04:03,810 --> 00:04:08,430 On s'attendait à ce que, potentiellement, cette erreur 77 00:04:08,630 --> 00:04:09,390 soit présente. 78 00:04:09,700 --> 00:04:13,330 Et ensuite, une erreur c'est une condition qu'on n'a même pas testée. 79 00:04:13,530 --> 00:04:15,760 En fait, c'est quelque chose qui se produit, par exemple 80 00:04:15,960 --> 00:04:18,290 une exception qui est levée et cetera auquel on ne s'attendait 81 00:04:18,490 --> 00:04:19,820 même pas au moment de l'écriture du test. 82 00:04:20,680 --> 00:04:21,700 Ce sont 2 cas bien distincts. 83 00:04:23,360 --> 00:04:26,520 Comment est-ce qu'on fait dans un test lorsqu'on veut 84 00:04:26,720 --> 00:04:31,360 tester qu'un bout de code lève une 85 00:04:31,560 --> 00:04:35,600 exception. Par exemple, je veux tester que set new remove 86 00:04:35,800 --> 00:04:40,110 1, donc ce bout de code va lever l'exception not found, 87 00:04:40,370 --> 00:04:42,390 puisque si je fais Set new, c'est forcément un ensemble 88 00:04:42,590 --> 00:04:44,450 vide, donc j'essaye de retirer un élément d'un ensemble 89 00:04:44,650 --> 00:04:47,510 vide, ça n'a pas de sens. Donc, ça va lever une exception not found. 90 00:04:47,840 --> 00:04:51,180 Dans mon test j'utilise should raise. 91 00:04:51,380 --> 00:04:54,180 Je passe un block. Au moment de l'évaluation de block, si 92 00:04:54,380 --> 00:04:56,640 une exception est levée et que l'exception c'est bien Not 93 00:04:56,840 --> 00:04:59,280 Found, alors le test sera vert, sera OK. 94 00:05:01,020 --> 00:05:03,350 Je peux aussi tester l'inverse, tester qu'un morceau de 95 00:05:03,550 --> 00:05:07,540 code ne lève pas d'exception. Ici, j'utilise la méthode self shouldnt raise. 96 00:05:08,860 --> 00:05:12,670 Ce morceau de code ne doit pas lever l'exception NotFound. 97 00:05:14,020 --> 00:05:16,430 On peut au moment de l'écriture de plusieurs tests, quand 98 00:05:16,630 --> 00:05:18,820 on en écrit plein, se rendre compte qu'on a des doublons 99 00:05:19,640 --> 00:05:21,580 au moment de l'écriture du contexte du test. 100 00:05:22,010 --> 00:05:24,520 Par exemple, ici j'écris un autre test pour les sets. 101 00:05:24,720 --> 00:05:28,380 Donc, testOccurrence et on voit qu'ici, dans le contexte, 102 00:05:28,580 --> 00:05:31,670 je vais recréer encore un nouveau set vide. 103 00:05:32,090 --> 00:05:35,440 A chaque fois que je vais écrire des tests pour un set, 104 00:05:35,640 --> 00:05:37,850 je vais à chaque fois faire Set new au début dans le contexte. 105 00:05:38,210 --> 00:05:40,410 Ce qu'on aimerait, c'est ne pas répéter à chaque fois 106 00:05:40,610 --> 00:05:41,370 cette ligne dans tous nos tests. 107 00:05:41,570 --> 00:05:44,590 Pour ne pas avoir à les répéter, pour pouvoir factoriser 108 00:05:44,790 --> 00:05:47,610 ça quelque part ailleurs, on a une solution. 109 00:05:48,260 --> 00:05:50,830 La solution en S-unit, c'est d'utiliser les méthodes 110 00:05:51,030 --> 00:05:55,210 setUp pour factoriser toutes les initialisations 111 00:05:55,710 --> 00:05:57,560 avant l'exécution d'un test. 112 00:05:57,760 --> 00:06:00,960 En fait, ce qui se passe, c'est qu'au moment de l'exécution 113 00:06:01,160 --> 00:06:03,880 d'un test, juste avant qu'une méthode qui commence par la 114 00:06:04,080 --> 00:06:07,440 chaîne test soit exécutée, on va déclencher l'exécution 115 00:06:07,640 --> 00:06:10,730 de la méthode Set up, poser le contexte, une bonne fois. 116 00:06:11,440 --> 00:06:15,800 On va réaliser, pendant le test, les stimulis et le 117 00:06:16,000 --> 00:06:19,380 check, les assertions et à la fin de l'exécution du test, 118 00:06:20,380 --> 00:06:23,880 qu'il ait échoué ou pas d'ailleurs, on va exécuter la 119 00:06:24,080 --> 00:06:26,680 méthode #tearDown qui va permettre de faire le nettoyage 120 00:06:27,340 --> 00:06:29,350 de toutes les ressources qui devraient être libérées par exemple. 121 00:06:29,920 --> 00:06:33,230 Si on regarde l'exécution de plusieurs méthodes tests, c'est facile. 122 00:06:33,600 --> 00:06:36,530 On va avoir l'exécution de Set up, une première méthode 123 00:06:36,730 --> 00:06:37,710 test qui est exécutée ici. 124 00:06:37,950 --> 00:06:40,210 L'exécution tearDown pour nettoyer, une nouvelle 125 00:06:40,410 --> 00:06:42,910 exécution de Set up, l'exécution d'un nouveau test, 126 00:06:43,370 --> 00:06:46,500 tearDown SetUp, l'exécution d'un test et tearDown. 127 00:06:47,940 --> 00:06:50,900 Ça nous permet de factoriser la mise en place du contexte 128 00:06:51,280 --> 00:06:53,090 et le nettoyage des ressources dans 2 méthodes 129 00:06:53,290 --> 00:06:54,050 particulières, setUp et tearDown. 130 00:06:54,250 --> 00:06:57,740 A quoi ça ressemble ? 131 00:06:58,840 --> 00:07:02,000 Dans notre exemple, si je prends le setTestCase, je peux 132 00:07:02,200 --> 00:07:05,400 mettre en place définir la méthode setUp dans lequel j'écris 133 00:07:05,600 --> 00:07:09,390 empty egal set new. Donc, empty devient une variable d'instance 134 00:07:09,590 --> 00:07:11,050 de la classe set test case. 135 00:07:12,590 --> 00:07:15,680 Et puis dans ma méthode de test, je peux directement 136 00:07:15,880 --> 00:07:18,700 utiliser la variable d'instance empty qui a été 137 00:07:18,900 --> 00:07:22,280 correctement initialisée, puisque avant l'exécution de la 138 00:07:22,480 --> 00:07:25,460 méthode testOccurence la méthode setUp a été 139 00:07:29,790 --> 00:07:30,550 exécutée. 140 00:07:30,750 --> 00:07:34,450 Si on regarde l'organisation des classes au sein du coeur 141 00:07:34,650 --> 00:07:37,510 de SUnit, comme je disais, il n'y a pas beaucoup de classes, il y en 4. 142 00:07:37,850 --> 00:07:42,270 Donc un TestCase, ce n'est plus ni moins qu'un test qui 143 00:07:42,470 --> 00:07:44,610 vérifie que certaines conditions sont vraies dans un 144 00:07:44,810 --> 00:07:48,430 contexte donné, donc il y a un testCase il a une méthode 145 00:07:48,630 --> 00:07:52,210 setUp, une méthode tearDown et puis un ensemble de méthode test. 146 00:07:53,410 --> 00:07:56,250 On écrira tout le temps des sous-classes de la classe testCase. 147 00:07:56,450 --> 00:08:01,110 Ces TestCase sont agrégés dans une 148 00:08:01,310 --> 00:08:05,920 testSuite, dans une suite de test, et on peut 149 00:08:06,450 --> 00:08:08,330 lancer l'exécution d'une suite complète. 150 00:08:08,750 --> 00:08:11,220 Quand on lance l'exécution d'une suite, on obtient un 151 00:08:11,420 --> 00:08:14,370 résultat et ce résultat est une instance de TestResult, 152 00:08:14,570 --> 00:08:19,020 ici, qui nous dit combien de tests ont passé, 153 00:08:19,560 --> 00:08:21,780 combien de tests ont été exécutés, combien de tests ont 154 00:08:22,000 --> 00:08:25,600 potentiellement rencontré des failures et des erreurs. 155 00:08:27,350 --> 00:08:32,120 On a aussi la notion de testResource qui permet de 156 00:08:32,320 --> 00:08:33,890 définir des ressources pour tout un testSuite. 157 00:08:36,340 --> 00:08:40,350 Le testCase, comme je le disais, ça représente un test, c'est 158 00:08:40,550 --> 00:08:44,030 une méthode qui commence par test définie sur une sous-classe de testCase. 159 00:08:45,490 --> 00:08:48,180 Une testSuite, c'est un groupe de test, ce sont toutes 160 00:08:48,380 --> 00:08:51,680 les méthodes test case définies dans une classe, voire plusieurs classes. 161 00:08:52,570 --> 00:08:55,510 Et puis un tesResult ça va être un résultat de l'exécution 162 00:08:55,710 --> 00:08:56,470 de plusieurs tests. 163 00:08:58,410 --> 00:09:02,840 Une ressource est un objet qui va permettre d' 164 00:09:03,040 --> 00:09:06,380 initialiser un ensemble de ressources, qui sont coûteuses 165 00:09:06,580 --> 00:09:08,220 à initialiser en temps normal, et qu'on ne veut 166 00:09:08,420 --> 00:09:10,220 initialiser qu'une seule fois pour un ensemble de tests. 167 00:09:10,660 --> 00:09:12,870 On met en place un testresource, on l'initialise une 168 00:09:13,070 --> 00:09:16,840 fois, on l'exécute plein de tests et ensuite on pourra la libérer à la fin. 169 00:09:18,000 --> 00:09:21,580 Ce qu'il faut retenir, c'est comment est-ce que vous 170 00:09:21,780 --> 00:09:23,780 pouvez écrire des tests. Ecrire des tests, c'est 171 00:09:24,000 --> 00:09:26,180 extrêmement simple, il suffit d'écrire une sous-classe de 172 00:09:26,380 --> 00:09:29,210 la classe testCase, définir des méthodes sur celle-ci qui 173 00:09:29,410 --> 00:09:32,820 commencent par test, et puis à l'intérieur mettre en 174 00:09:33,020 --> 00:09:35,150 place un contexte, envoyer les stimulis et tester les 175 00:09:35,350 --> 00:09:38,110 assertions qui devraient être vraies. 176 00:09:38,310 --> 00:09:39,710 On veut réutiliser les contextes. 177 00:09:40,020 --> 00:09:42,640 Pour les réutiliser à travers plusieurs méthodes test, on 178 00:09:42,840 --> 00:09:44,840 les factorise dans une méthode setUp par exemple. 179 00:09:47,410 --> 00:09:50,540 En résumé, dans cette séquence on a vu le framework de 180 00:09:50,740 --> 00:09:54,690 test SUnit, qui est extrêmement simple à utiliser et 181 00:09:54,890 --> 00:09:57,150 extrêmement efficace pour mettre en place du développement agile. 182 00:09:58,000 --> 00:09:59,610 Je vous encourage vivement à l'utiliser. 183 00:09:59,810 --> 00:10:01,510 Définir des tests, c'est extrêmement facile. 184 00:10:01,750 --> 00:10:03,680 Le gros avantage, c'est qu'on peut exécuter, une fois qu'on 185 00:10:03,880 --> 00:10:08,020 l'a écrit une fois, des millions de fois le même test et 186 00:10:08,220 --> 00:10:11,220 c'est extrêmement pratique pour être sûr que son code 187 00:10:11,420 --> 00:10:13,640 fonctionne encore, même si on a modifié des choses et 188 00:10:13,840 --> 00:10:15,310 qu'il y a des effets de bord qui se sont produits, on 189 00:10:15,510 --> 00:10:20,020 peut les détecter si on a été assez couvrant dans les tests qu'on a écrit. 190 00:10:21,230 --> 00:10:24,170 On peut aller plus loin sur l'écriture de test en 191 00:10:24,370 --> 00:10:26,530 utilisant des dot frameworks, typiquement des frameworks 192 00:10:26,730 --> 00:10:29,520 de Mock comme BabyMock, et caetera, pour avoir d'autres 193 00:10:29,720 --> 00:10:32,310 styles de tests ou d'écritures de tests. 194 00:10:34,600 --> 00:10:37,060 Je vous encourage à utiliser de nombreux tests et à 195 00:10:37,260 --> 00:10:38,280 écrire de nombreux tests dans vos programmes.