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
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Documentation SimpleTest : tester des scripts web</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 testeur web</h1>
This page...
<ul>
<li>
Réussir à <a href="#telecharger">télécharger une page web</a>
</li>
<li>
Tester le <a href="#contenu">contenu de la page</a>
</li>
<li>
<a href="#navigation">Naviguer sur un site web</a> pendant le test
</li>
<li>
Méthodes pour <a href="#requete">modifier une requête</a> et pour déboguer
</li>
</ul>
<div class="content">
<p><a class="target" name="telecharger"><h2>Télécharger une page</h2></a></p>
<p>
Tester des classes c'est très bien.
Reste que PHP est avant tout un langage
pour créer des fonctionnalités à l'intérieur de pages web.
Comment pouvons tester la partie de devant
-- celle de l'interface -- dans nos applications en PHP ?
Etant donné qu'une page web n'est constituée que de texte,
nous devrions pouvoir les examiner exactement
comme n'importe quelle autre donnée de test.
</p>
<p>
Cela nous amène à une situation délicate.
Si nous testons dans un niveau trop bas,
vérifier des balises avec un motif ad hoc par exemple,
nos tests seront trop fragiles. Le moindre changement
dans la présentation pourrait casser un grand nombre de test.
Si nos tests sont situés trop haut, en utilisant
une version fantaisie du moteur de template pour
donner un cas précis, alors nous perdons complètement
la capacité à automatiser certaines classes de test.
Par exemple, l'interaction entre des formulaires
et la navigation devra être testé manuellement.
Ces types de test sont extrêmement fastidieux
et plutôt sensibles aux erreurs.
</p>
<p>
SimpleTest comprend une forme spéciale de scénario
de test pour tester les actions d'une page web.
<span class="new_code">WebTestCase</span> inclut des facilités pour la navigation,
des vérifications sur le contenu
et les cookies ainsi que la gestion des formulaires.
Utiliser ces scénarios de test ressemble
fortement à <span class="new_code">UnitTestCase</span>...
<pre>
<strong>class TestOfLastcraft extends WebTestCase {
}</strong>
</pre>
Ici nous sommes sur le point de tester
le site de <a href="http://www.lastcraft.com/">Last Craft</a>.
Si ce scénario de test est situé dans un fichier appelé
<em>lastcraft_test.php</em> alors il peut être chargé
dans un script de lancement tout comme des tests unitaires...
<pre>
<?php
require_once('simpletest/autorun.php');<strong>
require_once('simpletest/web_tester.php');</strong>
SimpleTest::prefer(new TextReporter());
class WebTests extends TestSuite {
function WebTests() {
$this->TestSuite('Web site tests');<strong>
$this->addFile('lastcraft_test.php');</strong>
}
}
?>
</pre>
J'utilise ici le rapporteur en mode texte
pour mieux distinguer le contenu au format HTML
du résultat du test proprement dit.
</p>
<p>
Rien n'est encore testé. Nous pouvons télécharger
la page d'accueil en utilisant la méthode <span class="new_code">get()</span>...
<pre>
class TestOfLastcraft extends WebTestCase {
<strong>
function testHomepage() {
$this->assertTrue($this->get('http://www.lastcraft.com/'));
}</strong>
}
</pre>
La méthode <span class="new_code">get()</span> renverra "true"
uniquement si le contenu de la page a bien été téléchargé.
C'est un moyen simple, mais efficace pour vérifier
qu'une page web a bien été délivré par le serveur web.
Cependant le contenu peut révéler être une erreur 404
et dans ce cas notre méthode <span class="new_code">get()</span> renverrait encore un succès.
</p>
<p>
En supposant que le serveur web pour le site Last Craft
soit opérationnel (malheureusement ce n'est pas toujours le cas),
nous devrions voir...
<pre class="shell">
Web site tests
OK
Test cases run: 1/1, Failures: 0, Exceptions: 0
</pre>
Nous avons vérifié qu'une page, de n'importe quel type,
a bien été renvoyée. Nous ne savons pas encore
s'il s'agit de celle que nous souhaitions.
</p>
<p><a class="target" name="contenu"><h2>Tester le contenu d'une page</h2></a></p>
<p>
Pour obtenir la confirmation que la page téléchargée
est bien celle que nous attendions,
nous devons vérifier son contenu.
<pre>
class TestOfLastcraft extends WebTestCase {
function testHomepage() {<strong>
$this->get('http://www.lastcraft.com/');
$this->assertWantedPattern('/why the last craft/i');</strong>
}
}
</pre>
La page obtenue par le dernier téléchargement est
placée dans un buffer au sein même du scénario de test.
Il n'est donc pas nécessaire de s'y référer directement.
La correspondance du motif est toujours effectuée
par rapport à ce buffer.
</p>
<p>
Voici une liste possible d'assertions sur le contenu...
<table><tbody>
<tr>
<td><span class="new_code">assertWantedPattern($pattern)</span></td>
<td>Vérifier une correspondance sur le contenu via une expression rationnelle Perl</td>
</tr>
<tr>
<td><span class="new_code">assertNoUnwantedPattern($pattern)</span></td>
<td>Une expression rationnelle Perl pour vérifier une absence</td>
</tr>
<tr>
<td><span class="new_code">assertTitle($title)</span></td>
<td>Passe si le titre de la page correspond exactement</td>
</tr>
<tr>
<td><span class="new_code">assertLink($label)</span></td>
<td>Passe si un lien avec ce texte est présent</td>
</tr>
<tr>
<td><span class="new_code">assertNoLink($label)</span></td>
<td>Passe si aucun lien avec ce texte est présent</td>
</tr>
<tr>
<td><span class="new_code">assertLinkById($id)</span></td>
<td>Passe si un lien avec cet attribut d'identification est présent</td>
</tr>
<tr>
<td><span class="new_code">assertField($name, $value)</span></td>
<td>Passe si une balise input avec ce nom contient cette valeur</td>
</tr>
<tr>
<td><span class="new_code">assertFieldById($id, $value)</span></td>
<td>Passe si une balise input avec cet identifiant contient cette valeur</td>
</tr>
<tr>
<td><span class="new_code">assertResponse($codes)</span></td>
<td>Passe si la réponse HTTP trouve une correspondance dans la liste</td>
</tr>
<tr>
<td><span class="new_code">assertMime($types)</span></td>
<td>Passe si le type MIME se retrouve dans cette liste</td>
</tr>
<tr>
<td><span class="new_code">assertAuthentication($protocol)</span></td>
<td>Passe si l'authentification provoquée est de ce type de protocole</td>
</tr>
<tr>
<td><span class="new_code">assertNoAuthentication()</span></td>
<td>Passe s'il n'y pas d'authentification provoquée en cours</td>
</tr>
<tr>
<td><span class="new_code">assertRealm($name)</span></td>
<td>Passe si le domaine provoqué correspond</td>
</tr>
<tr>
<td><span class="new_code">assertHeader($header, $content)</span></td>
<td>Passe si une entête téléchargée correspond à cette valeur</td>
</tr>
<tr>
<td><span class="new_code">assertNoUnwantedHeader($header)</span></td>
<td>Passe si une entête n'a pas été téléchargé</td>
</tr>
<tr>
<td><span class="new_code">assertHeaderPattern($header, $pattern)</span></td>
<td>Passe si une entête téléchargée correspond à cette expression rationnelle Perl</td>
</tr>
<tr>
<td><span class="new_code">assertCookie($name, $value)</span></td>
<td>Passe s'il existe un cookie correspondant</td>
</tr>
<tr>
<td><span class="new_code">assertNoCookie($name)</span></td>
<td>Passe s'il n'y a pas de cookie avec un tel nom</td>
</tr>
</tbody></table>
Comme d'habitude avec les assertions de SimpleTest,
elles renvoient toutes "false" en cas d'échec
et "true" si c'est un succès.
Elles renvoient aussi un message de test optionnel :
vous pouvez l'ajouter dans votre propre message en utilisant "%s".
</p>
<p>
A présent nous pourrions effectué le test sur le titre uniquement...
<pre>
<strong>$this->assertTitle('The Last Craft?');</strong>
</pre>
En plus d'une simple vérification sur le contenu HTML,
nous pouvons aussi vérifier que le type MIME est bien d'un type acceptable...
<pre>
<strong>$this->assertMime(array('text/plain', 'text/html'));</strong>
</pre>
Plus intéressant encore est la vérification sur
le code de la réponse HTTP. Pareillement au type MIME,
nous pouvons nous assurer que le code renvoyé se trouve
bien dans un liste de valeurs possibles...
<pre>
class TestOfLastcraft extends WebTestCase {
function testHomepage() {
$this->get('http://simpletest.sourceforge.net/');<strong>
$this->assertResponse(200);</strong>
}
}
</pre>
Ici nous vérifions que le téléchargement s'est
bien terminé en ne permettant qu'une réponse HTTP 200.
Ce test passera, mais ce n'est pas la meilleure façon de procéder.
Il n'existe aucune page sur <em>http://simpletest.sourceforge.net/</em>,
à la place le serveur renverra une redirection vers
<em>http://www.lastcraft.com/simple_test.php</em>.
<span class="new_code">WebTestCase</span> suit automatiquement trois
de ces redirections. Les tests sont quelque peu plus
robustes de la sorte. Surtout qu'on est souvent plus intéressé
par l'interaction entre les pages que de leur simple livraison.
Si les redirections se révèlent être digne d'intérêt,
il reste possible de les supprimer...
<pre>
class TestOfLastcraft extends WebTestCase {
function testHomepage() {<strong>
$this->setMaximumRedirects(0);</strong>
$this->get('http://simpletest.sourceforge.net/');
$this->assertResponse(200);
}
}
</pre>
Alors l'assertion échoue comme prévue...
<pre class="shell">
Web site tests
1) Expecting response in [200] got [302]
in testhomepage
in testoflastcraft
in lastcraft_test.php
FAILURES!!!
Test cases run: 1/1, Failures: 1, Exceptions: 0
</pre>
Nous pouvons modifier le test pour accepter les redirections...
<pre>
class TestOfLastcraft extends WebTestCase {
function testHomepage() {
$this->setMaximumRedirects(0);
$this->get('http://simpletest.sourceforge.net/');
$this->assertResponse(<strong>array(301, 302, 303, 307)</strong>);
}
}
</pre>
Maitenant ça passe.
</p>
<p><a class="target" name="navigation"><h2>Navigeur dans un site web</h2></a></p>
<p>
Les utilisateurs ne naviguent pas souvent en tapant les URLs,
mais surtout en cliquant sur des liens et des boutons.
Ici nous confirmons que les informations sur le contact
peuvent être atteintes depuis la page d'accueil...
<pre>
class TestOfLastcraft extends WebTestCase {
...
function testContact() {
$this->get('http://www.lastcraft.com/');<strong>
$this->clickLink('About');
$this->assertTitle('About Last Craft');</strong>
}
}
</pre>
Le paramètre est le texte du lien.
</p>
<p>
Il l'objectif est un bouton plutôt qu'une balise ancre,
alors <span class="new_code">clickSubmit()</span> doit être utilisé avec
le titre du bouton...
<pre>
<strong>$this->clickSubmit('Go!');</strong>
</pre>
</p>
<p>
La liste des méthodes de navigation est...
<table><tbody>
<tr>
<td><span class="new_code">get($url, $parameters)</span></td>
<td>Envoie une requête GET avec ces paramètres</td>
</tr>
<tr>
<td><span class="new_code">post($url, $parameters)</span></td>
<td>Envoie une requête POST avec ces paramètres</td>
</tr>
<tr>
<td><span class="new_code">head($url, $parameters)</span></td>
<td>Envoie une requête HEAD sans remplacer le contenu de la page</td>
</tr>
<tr>
<td><span class="new_code">retry()</span></td>
<td>Relance la dernière requête</td>
</tr>
<tr>
<td><span class="new_code">back()</span></td>
<td>Identique au bouton "Précédent" du navigateur</td>
</tr>
<tr>
<td><span class="new_code">forward()</span></td>
<td>Identique au bouton "Suivant" du navigateur</td>
</tr>
<tr>
<td><span class="new_code">authenticate($name, $password)</span></td>
<td>Re-essaye avec une tentative d'authentification</td>
</tr>
<tr>
<td><span class="new_code">getFrameFocus()</span></td>
<td>Le nom de la fenêtre en cours d'utilisation</td>
</tr>
<tr>
<td><span class="new_code">setFrameFocusByIndex($choice)</span></td>
<td>Change le focus d'une fenêtre en commençant par 1</td>
</tr>
<tr>
<td><span class="new_code">setFrameFocus($name)</span></td>
<td>Change le focus d'une fenêtre en utilisant son nom</td>
</tr>
<tr>
<td><span class="new_code">clearFrameFocus()</span></td>
<td>Revient à un traitement de toutes les fenêtres comme une seule</td>
</tr>
<tr>
<td><span class="new_code">clickSubmit($label)</span></td>
<td>Clique sur le premier bouton avec cette étiquette</td>
</tr>
<tr>
<td><span class="new_code">clickSubmitByName($name)</span></td>
<td>Clique sur le bouton avec cet attribut de nom</td>
</tr>
<tr>
<td><span class="new_code">clickSubmitById($id)</span></td>
<td>Clique sur le bouton avec cet attribut d'identification</td>
</tr>
<tr>
<td><span class="new_code">clickImage($label, $x, $y)</span></td>
<td>Clique sur une balise input de type image par son titre (title="*") our son texte alternatif (alt="*")</td>
</tr>
<tr>
<td><span class="new_code">clickImageByName($name, $x, $y)</span></td>
<td>Clique sur une balise input de type image par son attribut (name="*")</td>
</tr>
<tr>
<td><span class="new_code">clickImageById($id, $x, $y)</span></td>
<td>Clique sur une balise input de type image par son identifiant (id="*")</td>
</tr>
<tr>
<td><span class="new_code">submitFormById($id)</span></td>
<td>Soumet un formulaire sans valeur de soumission</td>
</tr>
<tr>
<td><span class="new_code">clickLink($label, $index)</span></td>
<td>Clique sur une ancre avec ce texte d'étiquette visible</td>
</tr>
<tr>
<td><span class="new_code">clickLinkById($id)</span></td>
<td>Clique sur une ancre avec cet attribut d'identification</td>
</tr>
</tbody></table>
</p>
<p>
Les paramètres dans les méthodes <span class="new_code">get()</span>,
<span class="new_code">post()</span> et <span class="new_code">head()</span> sont optionnels.
Le téléchargement via HTTP HEAD ne modifie pas
le contexte du navigateur, il se limite au chargement des cookies.
Cela peut être utilise lorsqu'une image ou une feuille de style
initie un cookie pour bloquer un robot trop entreprenant.
</p>
<p>
Les commandes <span class="new_code">retry()</span>, <span class="new_code">back()</span>
et <span class="new_code">forward()</span> fonctionnent exactement comme
dans un navigateur. Elles utilisent l'historique pour
relancer les pages. Une technique bien pratique pour
vérifier les effets d'un bouton retour sur vos formulaires.
</p>
<p>
Les méthodes sur les fenêtres méritent une petite explication.
Par défaut, une page avec des fenêtres est traitée comme toutes
les autres. Le contenu sera vérifié à travers l'ensemble de
la "frameset", par conséquent un lien fonctionnera,
peu importe la fenêtre qui contient la balise ancre.
Vous pouvez outrepassé ce comportement en exigeant
le focus sur une unique fenêtre. Si vous réalisez cela,
toutes les recherches et toutes les actions se limiteront
à cette unique fenêtre, y compris les demandes d'authentification.
Si un lien ou un bouton n'est pas dans la fenêtre en focus alors
il ne peut pas être cliqué.
</p>
<p>
Tester la navigation sur des pages fixes ne vous alerte que
quand vous avez cassé un script entier.
Pour des pages fortement dynamiques,
un forum de discussion par exemple,
ça peut être crucial pour vérifier l'état de l'application.
Pour la plupart des applications cependant,
la logique vraiment délicate se situe dans la gestion
des formulaires et des sessions.
Heureusement SimpleTest aussi inclut
<a href="form_testing_documentation.html">
des outils pour tester des formulaires web</a>.
</p>
<p><a class="target" name="requete"><h2>Modifier la requête</h2></a></p>
<p>
Bien que SimpleTest n'ait pas comme objectif
de contrôler des erreurs réseau, il contient quand même
des méthodes pour modifier et déboguer les requêtes qu'il lance.
Voici une autre liste de méthode...
<table><tbody>
<tr>
<td><span class="new_code">getTransportError()</span></td>
<td>La dernière erreur de socket</td>
</tr>
<tr>
<td><span class="new_code">getUrl()</span></td>
<td>La localisation courante</td>
</tr>
<tr>
<td><span class="new_code">showRequest()</span></td>
<td>Déverse la requête sortante</td>
</tr>
<tr>
<td><span class="new_code">showHeaders()</span></td>
<td>Déverse les entêtes d'entrée</td>
</tr>
<tr>
<td><span class="new_code">showSource()</span></td>
<td>Déverse le contenu brut de la page HTML</td>
</tr>
<tr>
<td><span class="new_code">ignoreFrames()</span></td>
<td>Ne recharge pas les framesets</td>
</tr>
<tr>
<td><span class="new_code">setCookie($name, $value)</span></td>
<td>Initie un cookie à partir de maintenant</td>
</tr>
<tr>
<td><span class="new_code">addHeader($header)</span></td>
<td>Ajoute toujours cette entête à la requête</td>
</tr>
<tr>
<td><span class="new_code">setMaximumRedirects($max)</span></td>
<td>S'arrête après autant de redirections</td>
</tr>
<tr>
<td><span class="new_code">setConnectionTimeout($timeout)</span></td>
<td>Termine la connexion après autant de temps entre les bytes</td>
</tr>
<tr>
<td><span class="new_code">useProxy($proxy, $name, $password)</span></td>
<td>Effectue les requêtes à travers ce proxy d'URL</td>
</tr>
</tbody></table>
</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>
<a href="http://simpletest.org/api/">L'API du développeur pour 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>
|