1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Documentation SimpleTest : le rapporteur de test</title>
<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
</head>
<body>
<div class="menu_back"><div class="menu">
<a href="index.html">SimpleTest</a>
|
<a href="overview.html">Overview</a>
|
<a href="unit_test_documentation.html">Unit tester</a>
|
<a href="group_test_documentation.html">Group tests</a>
|
<a href="mock_objects_documentation.html">Mock objects</a>
|
<a href="partial_mocks_documentation.html">Partial mocks</a>
|
<a href="reporter_documentation.html">Reporting</a>
|
<a href="expectation_documentation.html">Expectations</a>
|
<a href="web_tester_documentation.html">Web tester</a>
|
<a href="form_testing_documentation.html">Testing forms</a>
|
<a href="authentication_documentation.html">Authentication</a>
|
<a href="browser_documentation.html">Scriptable browser</a>
</div></div>
<h1>Documentation sur le rapporteur de test</h1>
This page...
<ul>
<li>
Afficher <a href="#html">les résultats en HTML</a>
</li>
<li>
Afficher et <a href="#autres">rapporter les résultats</a>
dans d'autres formats
</li>
<li>
Utilisé <a href="#cli">SimpleTest depuis la ligne de commande</a>
</li>
<li>
<a href="#xml">Utiliser XML</a> pour des tests distants
</li>
</ul>
<div class="content">
<p>
SimpleTest suit plutôt plus que moins le modèle MVC (Modèle-Vue-Contrôleur).
Les classes "reporter" sont les vues et les modèles
sont vos scénarios de test et leur hiérarchie.
Le contrôleur est le plus souvent masqué à l'utilisateur
de SimpleTest à moins de vouloir changer la façon
dont les tests sont effectivement exécutés,
auquel cas il est possible de surcharger les objets
"runner" (ceux de l'exécuteur) depuis l'intérieur
d'un scénario de test. Comme d'habitude avec MVC,
le contrôleur est plutôt indéfini et il existe d'autres endroits
pour contrôler l'exécution des tests.
</p>
<p><a class="target" name="html"><h2>Les résultats rapportés au format HTML</h2></a></p>
<p>
L'affichage par défaut est minimal à l'extrême.
Il renvoie le succès ou l'échec avec les barres conventionnelles
- rouge et verte - et affichent une trace d'arborescence
des groupes de test pour chaque assertion erronée. Voici un tel échec...
<div class="demo">
<h1>File test</h1>
<span class="fail">Fail</span>: createnewfile->True assertion failed.<br>
<div style="padding: 8px; margin-top: 1em; background-color: red; color: white;">1/1 test cases complete.
<strong>0</strong> passes, <strong>1</strong> fails and <strong>0</strong> exceptions.</div>
</div>
Alors qu'ici tous les tests passent...
<div class="demo">
<h1>File test</h1>
<div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
<strong>1</strong> passes, <strong>0</strong> fails and <strong>0</strong> exceptions.</div>
</div>
La bonne nouvelle, c'est qu'il existe pas mal de points
dans la hiérarchie de l'affichage pour créer des sous-classes.
</p>
<p>
Pour l'affichage basé sur des pages web,
il y a la classe <span class="new_code">HtmlReporter</span> avec la signature suivante...
<pre>
class HtmlReporter extends SimpleReporter {
public HtmlReporter($encoding) { ... }
public makeDry(boolean $is_dry) { ... }
public void paintHeader(string $test_name) { ... }
public void sendNoCacheHeaders() { ... }
public void paintFooter(string $test_name) { ... }
public void paintGroupStart(string $test_name, integer $size) { ... }
public void paintGroupEnd(string $test_name) { ... }
public void paintCaseStart(string $test_name) { ... }
public void paintCaseEnd(string $test_name) { ... }
public void paintMethodStart(string $test_name) { ... }
public void paintMethodEnd(string $test_name) { ... }
public void paintFail(string $message) { ... }
public void paintPass(string $message) { ... }
public void paintError(string $message) { ... }
public void paintException(string $message) { ... }
public void paintMessage(string $message) { ... }
public void paintFormattedMessage(string $message) { ... }
protected string _getCss() { ... }
public array getTestList() { ... }
public integer getPassCount() { ... }
public integer getFailCount() { ... }
public integer getExceptionCount() { ... }
public integer getTestCaseCount() { ... }
public integer getTestCaseProgress() { ... }
}
</pre>
Voici ce que certaines de ces méthodes veulent dire.
Premièrement les méthodes d'affichage que vous voudrez probablement surcharger...
<ul class="api">
<li>
<span class="new_code">HtmlReporter(string $encoding)</span><br>
est le constructeur. Notez que le test unitaire initie
le lien à l'affichage plutôt que l'opposé.
L'affichage est principalement un receveur passif
des évènements de tests. Cela permet d'adapter
facilement l'affichage pour d'autres systèmes
en dehors des tests unitaires, tel le suivi
de la charge de serveurs.
L'"encoding" est le type d'encodage
que vous souhaitez utiliser pour l'affichage du test.
Pour pouvoir effectuer un rendu correct de la sortie
de débogage quand on utilise le testeur web,
il doit correspondre à l'encodage du site testé.
Les chaînes de caractères disponibles
sont indiquées dans la fonction PHP
<a href="http://www.php.net/manual/fr/function.htmlentities.php">html_entities()</a>.
</li>
<li>
<span class="new_code">void paintHeader(string $test_name)</span><br>
est appelé une fois, au début du test quand l'évènement
de démarrage survient. Le premier évènement de démarrage
est souvent délivré par le groupe de tests du niveau
le plus haut et donc c'est de là que le
<span class="new_code">$test_name</span> arrive.
Il peint les titres de la page, CSS, la balise "body", etc.
Il ne renvoie rien du tout (<span class="new_code">void</span>).
</li>
<li>
<span class="new_code">void paintFooter(string $test_name)</span><br>
est appelé à la toute fin du test pour fermer
les balises ouvertes par l'entête de la page.
Par défaut il affiche aussi la barre rouge ou verte
et le décompte final des résultats.
En fait la fin des tests arrive quand l'évènement
de fin de test arrive avec le même nom
que celui qui l'a initié au même niveau.
Le nid des tests en quelque sorte.
Fermer le dernier test finit l'affichage.
</li>
<li>
<span class="new_code">void paintMethodStart(string $test_name)</span><br>
est appelé au début de chaque méthode de test.
Normalement le nom vient de celui de la méthode.
Les autres évènements de départ de test
se comportent de la même manière sauf que
celui du groupe de tests indique au rapporteur
le nombre de scénarios de test qu'il contient.
De la sorte le rapporteur peut afficher une barre
de progrès au fur et à mesure que l'exécuteur
passe en revue les scénarios de test.
</li>
<li>
<span class="new_code">void paintMethodEnd(string $test_name)</span><br>
clôt le test lancé avec le même nom.
</li>
<li>
<span class="new_code">void paintFail(string $message)</span><br>
peint un échec. Par défaut il ne fait qu'afficher
le mot "fail", une trace d'arborescence
affichant la position du test en cours
et le message transmis par l'assertion.
</li>
<li>
<span class="new_code">void paintPass(string $message)</span><br>
ne fait rien, par défaut.
</li>
<li>
<span class="new_code">string _getCss()</span><br>
renvoie les styles CSS sous la forme d'une chaîne
à l'attention de la méthode d'entêtes d'une page.
Des styles additionnels peuvent être ajoutés ici
si vous ne surchargez pas les entêtes de la page.
Vous ne voudrez pas utiliser cette méthode dans
des entêtes d'une page surchargée si vous souhaitez
inclure le feuille de style CSS d'origine.
</li>
</ul>
Il y a aussi des accesseurs pour aller chercher l'information
sur l'état courant de la suite de test. Vous les utiliserez
pour enrichir l'affichage...
<ul class="api">
<li>
<span class="new_code">array getTestList()</span><br>
est la première méthode très commode pour les sous-classes.
Elle liste l'arborescence courante des tests
sous la forme d'une liste de noms de tests.
Le premier test -- celui le plus proche du coeur --
sera le premier dans la liste et la méthode de test
en cours sera la dernière.
</li>
<li>
<span class="new_code">integer getPassCount()</span><br>
renvoie le nombre de succès atteint. Il est nécessaire
pour l'affichage à la fin.
</li>
<li>
<span class="new_code">integer getFailCount()</span><br>
renvoie de la même manière le nombre d'échecs.
</li>
<li>
<span class="new_code">integer getExceptionCount()</span><br>
renvoie quant à lui le nombre d'erreurs.
</li>
<li>
<span class="new_code">integer getTestCaseCount()</span><br>
est le nombre total de scénarios lors de l'exécution des tests.
Il comprend aussi les tests groupés.
</li>
<li>
<span class="new_code">integer getTestCaseProgress()</span><br>
est le nombre de scénarios réalisés jusqu'à présent.
</li>
</ul>
Une modification simple : demander à l'HtmlReporter d'afficher
aussi bien les succès que les échecs et les erreurs...
<pre><strong>
class ShowPasses extends HtmlReporter {
function paintPass($message) {
parent::paintPass($message);
print "&<span class=\"pass\">Pass</span>: ";
$breadcrumb = $this->getTestList();
array_shift($breadcrumb);
print implode("-&gt;", $breadcrumb);
print "-&gt;$message<br />\n";
}
function _getCss() {
return parent::_getCss() . ' .pass { color: green; }';
}
}</strong>
</pre>
</p>
<p>
Une méthode qui a beaucoup fait jaser reste la méthode <span class="new_code">makeDry()</span>.
Si vous lancez cette méthode, sans paramètre,
sur le rapporteur avant que la suite de test
ne soit exécutée alors aucune méthode de test
ne sera appelée. Vous continuerez à avoir
les évènements entrants et sortants des méthodes
et scénarios de test, mais aucun succès ni échec ou erreur,
parce que le code de test ne sera pas exécuté.
</p>
<p>
La raison ? Pour permettre un affichage complexe
d'une IHM (ou GUI) qui permettrait la sélection
de scénarios de test individuels.
Afin de construire une liste de tests possibles,
ils ont besoin d'un rapport sur la structure du test
pour l'affichage, par exemple, d'une vue en arbre
de la suite de test. Avec un rapporteur lancé
sur une exécution sèche qui ne renverrait
que les évènements d'affichage, cela devient
facilement réalisable.
</p>
<p><a class="target" name="autre"><h2>Etendre le rapporteur</h2></a></p>
<p>
Plutôt que de modifier l'affichage existant,
vous voudrez peut-être produire une présentation HTML
complètement différente, ou même générer une version texte ou XML.
Plutôt que de surcharger chaque méthode dans
<span class="new_code">HtmlReporter</span> nous pouvons nous rendre
une étape plus haut dans la hiérarchie de classe vers
<span class="new_code">SimpleReporter</span> dans le fichier source <em>simple_test.php</em>.
</p>
<p>
Un affichage sans rien, un canevas vierge
pour votre propre création, serait...
<pre><strong>
require_once('simpletest/simple_test.php');</strong>
class MyDisplay extends SimpleReporter {<strong>
</strong>
function paintHeader($test_name) {
}
function paintFooter($test_name) {
}
function paintStart($test_name, $size) {<strong>
parent::paintStart($test_name, $size);</strong>
}
function paintEnd($test_name, $size) {<strong>
parent::paintEnd($test_name, $size);</strong>
}
function paintPass($message) {<strong>
parent::paintPass($message);</strong>
}
function paintFail($message) {<strong>
parent::paintFail($message);</strong>
}
}
</pre>
Aucune sortie ne viendrait de cette classe jusqu'à un ajout de votre part.
</p>
<p><a class="target" name="cli"><h2>Le rapporteur en ligne de commande</h2></a></p>
<p>
SimpleTest est aussi livré avec un rapporteur
en ligne de commande, minime lui aussi.
L'interface imite celle de JUnit,
sauf qu'elle envoie les messages d'erreur au fur
et à mesure de leur arrivée.
Pour utiliser le rapporteur en ligne de commande,
il suffit de l'intervertir avec celui de la version HTML...
<pre>
<?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
$test = &new GroupTest('File test');
$test->addTestFile('tests/file_test.php');
$test->run(<strong>new TextReporter()</strong>);
?>
</pre>
Et ensuite d'invoquer la suite de test à partir d'une ligne de commande...
<pre class="shell">
php file_test.php
</pre>
Bien sûr vous aurez besoin d'installer PHP
en ligne de commande. Une suite de test qui
passerait toutes ses assertions ressemble à...
<pre class="shell">
File test
OK
Test cases run: 1/1, Failures: 0, Exceptions: 0
</pre>
Un échec déclenche un affichage comme...
<pre class="shell">
File test
1) True assertion failed.
in createnewfile
FAILURES!!!
Test cases run: 1/1, Failures: 1, Exceptions: 0
</pre>
</p>
<p>
Une des principales raisons pour utiliser
une suite de test en ligne de commande tient
dans l'utilisation possible du testeur avec
un processus automatisé. Pour fonctionner comme
il faut dans des scripts shell le script de test
devrait renvoyer un code de sortie non-nul suite à un échec.
Si une suite de test échoue la valeur <span class="new_code">false</span>
est renvoyée par la méthode <span class="new_code">SimpleTest::run()</span>.
Nous pouvons utiliser ce résultat pour terminer le script
avec la bonne valeur renvoyée...
<pre>
<?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
$test = &new GroupTest('File test');
$test->addTestFile('tests/file_test.php');<strong>
exit ($test->run(new TextReporter()) ? 0 : 1);</strong>
?>
</pre>
Bien sûr l'objectif n'est pas de créer deux scripts de test,
l'un en ligne de commande et l'autre pour un navigateur web,
pour chaque suite de test.
Le rapporteur en ligne de commande inclut
une méthode pour déterminer l'environnement d'exécution...
<pre>
<?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');
$test = &new GroupTest('File test');
$test->addTestFile('tests/file_test.php');<strong>
if (TextReporter::inCli()) {</strong>
exit ($test->run(new TextReporter()) ? 0 : 1);<strong>
}</strong>
$test->run(new HtmlReporter());
?>
</pre>
Il s'agit là de la forme utilisée par SimpleTest lui-même.
</p>
<p><a class="target" name="xml"><h2>Test distant</h2></a></p>
<p>
SimpleTest est livré avec une classe <span class="new_code">XmlReporter</span>
utilisée pour de la communication interne.
Lors de son exécution, le résultat ressemble à...
<pre class="shell">
<?xml version="1.0"?>
<run>
<group size="4">
<name>Remote tests</name>
<group size="4">
<name>Visual test with 48 passes, 48 fails and 4 exceptions</name>
<case>
<name>testofunittestcaseoutput</name>
<test>
<name>testofresults</name>
<pass>This assertion passed</pass>
<fail>This assertion failed</fail>
</test>
<test>
...
</test>
</case>
</group>
</group>
</run>
</pre>
Vous pouvez utiliser ce format avec le parseur
fourni dans SimpleTest lui-même.
Il s'agit de <span class="new_code">SimpleTestXmlParser</span>
et se trouve <em>xml.php</em> à l'intérieur du paquet SimpleTest...
<pre>
<?php
require_once('simpletest/xml.php');
...
$parser = &new SimpleTestXmlParser(new HtmlReporter());
$parser->parse($test_output);
?>
</pre>
<span class="new_code">$test_output</span> devrait être au format XML,
à partir du rapporteur XML, et pourrait venir
d'une exécution en ligne de commande d'un scénario de test.
Le parseur envoie des évènements au rapporteur exactement
comme tout autre exécution de test.
Il y a des occasions bizarres dans lesquelles c'est en fait très utile.
</p>
<p>
Un problème des très grandes suites de test,
c'est qu'elles peuvent venir à bout de la limite de mémoire
par défaut d'un process PHP - 8Mb.
En plaçant la sortie des groupes de test dans du XML
et leur exécution dans des process différents,
le résultat peut être parsé à nouveau pour agréger
les résultats avec moins d'impact sur le test au premier niveau.
</p>
<p>
Parce que la sortie XML peut venir de n'importe où,
ça ouvre des possibilités d'agrégation d'exécutions de test
depuis des serveur distants.
Un scénario de test pour le réaliser existe déjà
à l'intérieur du framework SimpleTest, mais il est encore expérimental...
<pre>
<?php<strong>
require_once('../remote.php');</strong>
require_once('../reporter.php');
$test_url = ...;
$dry_url = ...;
$test = &new GroupTest('Remote tests');
$test->addTestCase(<strong>new RemoteTestCase($test_url, $dry_url)</strong>);
$test->run(new HtmlReporter());
?>
</pre>
<span class="new_code">RemoteTestCase</span> prend la localisation réelle
du lanceur de test, tout simplement un page web au format XML.
Il prend aussi l'URL d'un rapporteur initié
pour effectuer une exécution sèche.
Cette technique est employée pour que les progrès
soient correctement rapportés vers le haut.
<span class="new_code">RemoteTestCase</span> peut être ajouté à
une suite de test comme n'importe quel autre groupe de tests.
</p>
</div>
References and related information...
<ul>
<li>
La page du projet SimpleTest sur
<a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
</li>
<li>
La page de téléchargement de SimpleTest sur
<a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
</li>
<li>
L'<a href="http://simpletest.org/api/">API pour développeur de SimpleTest</a>
donne tous les détails sur les classes et les assertions disponibles.
</li>
</ul>
<div class="menu_back"><div class="menu">
<a href="index.html">SimpleTest</a>
|
<a href="overview.html">Overview</a>
|
<a href="unit_test_documentation.html">Unit tester</a>
|
<a href="group_test_documentation.html">Group tests</a>
|
<a href="mock_objects_documentation.html">Mock objects</a>
|
<a href="partial_mocks_documentation.html">Partial mocks</a>
|
<a href="reporter_documentation.html">Reporting</a>
|
<a href="expectation_documentation.html">Expectations</a>
|
<a href="web_tester_documentation.html">Web tester</a>
|
<a href="form_testing_documentation.html">Testing forms</a>
|
<a href="authentication_documentation.html">Authentication</a>
|
<a href="browser_documentation.html">Scriptable browser</a>
</div></div>
<div class="copyright">
Copyright<br>Marcus Baker 2006
</div>
</body>
</html>
|