web_tester_documentation.html 20.6 KB
Newer Older
zYne's avatar
zYne committed
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
<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">
<h2>
<a href="index.html">SimpleTest</a>
</h2>
<ul>
<li>
<a href="overview.html">Overview</a>
</li>
<li>
<a href="unit_test_documentation.html">Unit tester</a>
</li>
<li>
<a href="group_test_documentation.html">Group tests</a>
</li>
<li>
<a href="server_stubs_documentation.html">Server stubs</a>
</li>
<li>
<a href="mock_objects_documentation.html">Mock objects</a>
</li>
<li>
<a href="partial_mocks_documentation.html">Partial mocks</a>
</li>
<li>
<a href="reporter_documentation.html">Reporting</a>
</li>
<li>
<a href="expectation_documentation.html">Expectations</a>
</li>
<li>
<a href="web_tester_documentation.html">Web tester</a>
</li>
<li>
<a href="form_testing_documentation.html">Testing forms</a>
</li>
<li>
<a href="authentication_documentation.html">Authentication</a>
</li>
<li>
<a href="browser_documentation.html">Scriptable browser</a>
</li>
</ul>
</div>
</div>
<h1>Documentation sur le testeur web</h1>
<div class="content">
        <p>
<a class="target" name="telecharger">
<h2>T&eacute;l&eacute;charger une page</h2>
</a>
</p>
            <p>
                Tester des classes c'es tr&egrave;s bien. Reste que PHP est avant tout un langage pour cr&eacute;er des fonctionnalit&eacute;s &agrave; l'int&eacute;rieur de pages web. Comment pouvons tester la partie de devant -- celle de l'interface -- dans nos applications en PHP ? Etant donn&eacute; qu'une page web n'est constitu&eacute;e que de texte, nous devrions pouvoir les examiner exactement comme n'importe quelle autre donn&eacute;e de test.
            </p>
            <p>
                Cela nous am&egrave;ne &agrave; une situation d&eacute;licate. Si nous testons dans un niveau trop bas, v&eacute;rifier des balises avec un motif ad hoc par exemple, nos tests seront trop fragiles. Le moindre changement dans la pr&eacute;sentation pourrait casser un grand nombre de test. Si nos tests sont situ&eacute;s trop haut, en utilisant une version fantaisie du moteur de template pour donner un cas pr&eacute;cis, alors nous perdons compl&egrave;tement la capacit&eacute; &agrave; automatiser certaines classes de test. Par exemple, l'interaction entre des formulaires et la navigation devra &ecirc;tre test&eacute; manuellement. Ces types de test sont extr&ecirc;mement fastidieux et plut&ocirc;t sensibles aux erreurs.
            </p>
            <p>
                SimpleTest comprend une forme sp&eacute;ciale de sc&eacute;nario de test pour tester les actions d'une page web. <span class="new_code">WebTestCase</span> inclut des facilit&eacute;s pour la navigation, des v&eacute;rifications sur le contenu et les cookies ainsi que la gestion des formulaires. Utiliser ces sc&eacute;narios de test ressemble fortement &agrave; <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&eacute;nario de test est situ&eacute; dans un fichier appel&eacute; <em>lastcraft_test.php</em> alors il peut &ecirc;tre charg&eacute; dans un script de lancement tout comme des tests unitaires...
<pre>
&lt;?php<strong>
    require_once('simpletest/web_tester.php');</strong>
    require_once('simpletest/reporter.php');
    
    $test = &amp;new GroupTest('Web site tests');<strong>
    $test-&gt;addTestFile('lastcraft_test.php');</strong>
    exit ($test-&gt;run(new TextReporter()) ? 0 : 1);
?&gt;
</pre>
                J'utilise ici le rapporteur en mode texte pour mieux distinguer le contenu au format HTML du r&eacute;sultat du test proprement dit.
            </p>
            <p>
                Rien n'est encore test&eacute;. Nous pouvons t&eacute;l&eacute;charger la page d'accueil en utilisant la m&eacute;thode <span class="new_code">get()</span>...
<pre>
class TestOfLastcraft extends WebTestCase {
    <strong>
    function testHomepage() {
        $this-&gt;assertTrue($this-&gt;get('http://www.lastcraft.com/'));
    }</strong>
}
</pre>
                La m&eacute;thode <span class="new_code">get()</span> renverra "true" uniquement si le contenu de la page a bien &eacute;t&eacute; t&eacute;l&eacute;charg&eacute;. C'est un moyen simple, mais efficace pour v&eacute;rifier qu'une page web a bien &eacute;t&eacute; d&eacute;livr&eacute; par le serveur web. Cependant le contenu peut r&eacute;v&eacute;ler &ecirc;tre une erreur 404 et dans ce cas notre m&eacute;thode <span class="new_code">get()</span> renverrait encore un succ&egrave;s.
            </p>
            <p>
                En supposant que le serveur web pour le site Last Craft soit op&eacute;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&eacute;rifi&eacute; qu'une page, de n'importe quel type, a bien &eacute;t&eacute; renvoy&eacute;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&eacute;l&eacute;charg&eacute;e est bien celle que nous attendions, nous devons v&eacute;rifier son contenu.
<pre>
class TestOfLastcraft extends WebTestCase {
    
    function testHomepage() {<strong>
        $this-&gt;get('http://www.lastcraft.com/');
        $this-&gt;assertWantedPattern('/why the last craft/i');</strong>
    }
}
</pre>
                La page obtenue par le dernier t&eacute;l&eacute;chargement est plac&eacute;e dans un buffer au sein m&ecirc;me du sc&eacute;nario de test. Il n'est donc pas n&eacute;cessaire de s'y r&eacute;f&eacute;rer directement. La correspondance du motif est toujours effectu&eacute;e par rapport &agrave; 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&eacute;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&eacute;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&eacute;sent</td>
</tr>
                    <tr>
<td><span class="new_code">assertNoLink($label)</span></td><td>Passe si aucun lien avec ce texte est pr&eacute;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&eacute;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&eacute;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&eacute;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&eacute;e en cours</td>
</tr>
                    <tr>
<td><span class="new_code">assertRealm($name)</span></td><td>Passe si le domaine provoqu&eacute; correspond</td>
</tr>
                    <tr>
<td><span class="new_code">assertHeader($header, $content)</span></td><td>Passe si une ent&ecirc;te t&eacute;l&eacute;charg&eacute;e correspond &agrave; cette valeur</td>
</tr>
                    <tr>
<td><span class="new_code">assertNoUnwantedHeader($header)</span></td><td>Passe si une ent&ecirc;te n'a pas &eacute;t&eacute; t&eacute;l&eacute;charg&eacute;</td>
</tr>
                    <tr>
<td><span class="new_code">assertHeaderPattern($header, $pattern)</span></td><td>Passe si une ent&ecirc;te t&eacute;l&eacute;charg&eacute;e correspond &agrave; 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'&eacute;chec et "true" si c'est un succ&egrave;s. Elles renvoient aussi un message de test optionnel : vous pouvez l'ajouter dans votre propre message en utilisant "%s".
            </p>
            <p>
                A pr&eacute;sent nous pourrions effectu&eacute; le test sur le titre uniquement...
<pre>
<strong>$this-&gt;assertTitle('The Last Craft?');</strong>
</pre>
                En plus d'une simple v&eacute;rification sur le contenu HTML, nous pouvons aussi v&eacute;rifier que le type MIME est bien d'un type acceptable...
<pre>
<strong>$this-&gt;assertMime(array('text/plain', 'text/html'));</strong>
</pre>
                Plus int&eacute;ressant encore est la v&eacute;rification sur le code de la r&eacute;ponse HTTP. Pareillement au type MIME, nous pouvons nous assurer que le code renvoy&eacute; se trouve bien dans un liste de valeurs possibles...
<pre>
class TestOfLastcraft extends WebTestCase {
    
    function testHomepage() {
        $this-&gt;get('http://simpletest.sourceforge.net/');<strong>
        $this-&gt;assertResponse(200);</strong>
    }
}
</pre>
                Ici nous v&eacute;rifions que le t&eacute;l&eacute;chargement s'est bien termin&eacute; en ne permettant qu'une r&eacute;ponse HTTP 200.  Ce test passera, mais ce n'est pas la meilleure fa&ccedil;on de proc&eacute;der. Il n'existe aucune page sur <em>http://simpletest.sourceforge.net/</em>, &agrave; 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&eacute;ress&eacute; par l'interaction entre les pages que de leur simple livraison. Si les redirections se r&eacute;v&egrave;lent &ecirc;tre digne d'int&eacute;r&ecirc;t, il reste possible de les supprimer...
<pre>
class TestOfLastcraft extends WebTestCase {
    
    function testHomepage() {<strong>
        $this-&gt;setMaximumRedirects(0);</strong>
        $this-&gt;get('http://simpletest.sourceforge.net/');
        $this-&gt;assertResponse(200);
    }
}
</pre>
                Alors l'assertion &eacute;choue comme pr&eacute;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-&gt;setMaximumRedirects(0);
        $this-&gt;get('http://simpletest.sourceforge.net/');
        $this-&gt;assertResponse(<strong>array(301, 302, 303, 307)</strong>);
    }
}
</pre>
                Maitenant &ccedil;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 &ecirc;tre atteintes depuis la page d'accueil...
<pre>
class TestOfLastcraft extends WebTestCase {
    ...
    function testContact() {
        $this-&gt;get('http://www.lastcraft.com/');<strong>
        $this-&gt;clickLink('About');
        $this-&gt;assertTitle('About Last Craft');</strong>
    }
}
</pre>
                Le param&egrave;tre est le texte du lien.
            </p>
            <p>
                Il l'objectif est un bouton plut&ocirc;t qu'une balise ancre, alors <span class="new_code">clickSubmit()</span> doit &ecirc;tre utilis&eacute; avec le titre du bouton...
<pre>
<strong>$this-&gt;clickSubmit('Go!');</strong>
</pre>
            </p>
            <p>
                La liste des m&eacute;thodes de navigation est...
                <table>
<tbody>
                    <tr>
<td><span class="new_code">get($url, $parameters)</span></td><td>Envoie une requ&ecirc;te GET avec ces param&egrave;tres</td>
</tr>
                    <tr>
<td><span class="new_code">post($url, $parameters)</span></td><td>Envoie une requ&ecirc;te POST avec ces param&egrave;tres</td>
</tr>
                    <tr>
<td><span class="new_code">head($url, $parameters)</span></td><td>Envoie une requ&ecirc;te HEAD sans remplacer le contenu de la page</td>
</tr>
                    <tr>
<td><span class="new_code">retry()</span></td><td>Relance la derni&egrave;re requ&ecirc;te</td>
</tr>
                    <tr>
<td><span class="new_code">back()</span></td><td>Identique au bouton "Pr&eacute;c&eacute;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&ecirc;tre en cours d'utilisation</td>
</tr>
                    <tr>
<td><span class="new_code">setFrameFocusByIndex($choice)</span></td><td>Change le focus d'une fen&ecirc;tre en commen&ccedil;ant par 1</td>
</tr>
                    <tr>
<td><span class="new_code">setFrameFocus($name)</span></td><td>Change le focus d'une fen&ecirc;tre en utilisant son nom</td>
</tr>
                    <tr>
<td><span class="new_code">clearFrameFocus()</span></td><td>Revient &agrave; un traitement de toutes les fen&ecirc;tres comme une seule</td>
</tr>
                    <tr>
<td><span class="new_code">clickSubmit($label)</span></td><td>Clique sur le premier bouton avec cette &eacute;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 avec ce titre ou ce texte dans l'attribut alt</td>
</tr>
                    <tr>
<td><span class="new_code">clickImageByName($name, $x, $y)</span></td><td>Clique sur une balise input de type image avec ce nom</td>
</tr>
                    <tr>
<td><span class="new_code">clickImageById($id, $x, $y)</span></td><td>Clique sur une balise input de type image avec cet attribut d'identification</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 un ancre avec ce texte d'&eacute;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&egrave;tres dans les m&eacute;thodes <span class="new_code">get()</span>, <span class="new_code">post()</span> et <span class="new_code">head()</span> sont optionnels. Le t&eacute;l&eacute;chargement via  HTTP HEAD ne modifie pas le contexte du navigateur, il se limite au chargement des cookies. Cela peut &ecirc;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&eacute;rifier les effets d'un bouton retour sur vos formulaires.
            </p>
            <p>
                Les m&eacute;thodes sur les fen&ecirc;tres m&eacute;ritent une petite explication. Par d&eacute;faut, une page avec des fen&ecirc;tres est trait&eacute;e comme toutes les autres. Le contenu sera v&eacute;rifi&eacute; &agrave; travers l'ensemble de la "frameset", par cons&eacute;quent un lien fonctionnera, peu importe la fen&ecirc;tre qui contient la balise ancre. Vous pouvez outrepass&eacute; ce comportement en exigeant le focus sur une unique fen&ecirc;tre. Si vous r&eacute;alisez cela, toutes les recherches et toutes les actions se limiteront &agrave; cette unique fen&ecirc;tre, y compris les demandes d'authentification. Si un lien ou un bouton n'est pas dans la fen&ecirc;tre en focus alors il ne peut pas &ecirc;tre cliqu&eacute;.
            </p>
            <p>
                Tester la navigation sur des pages fixes ne vous alerte que quand vous avez cass&eacute; un script entier. Pour des pages fortement dynamiques, un forum de discussion par exemple, &ccedil;a peut &ecirc;tre crucial pour v&eacute;rifier l'&eacute;tat de l'application. Pour la plupart des applications cependant, la logique vraiment d&eacute;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&ecirc;te</h2>
</a>
</p>
            <p>
                Bien que SimpleTest n'ait pas comme objectif de contr&ocirc;ler des erreurs r&eacute;seau, il contient quand m&ecirc;me des m&eacute;thodes pour modifier et d&eacute;boguer les requ&ecirc;tes qu'il lance. Voici une autre liste de m&eacute;thode...
                <table>
<tbody>
                    <tr>
<td><span class="new_code">getTransportError()</span></td><td>La derni&egrave;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&eacute;verse la requ&ecirc;te sortante</td>
</tr>
                    <tr>
<td><span class="new_code">showHeaders()</span></td><td>D&eacute;verse les ent&ecirc;tes d'entr&eacute;e</td>
</tr>
                    <tr>
<td><span class="new_code">showSource()</span></td><td>D&eacute;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 &agrave; partir de maintenant</td>
</tr>
                    <tr>
<td><span class="new_code">addHeader($header)</span></td><td>Ajoute toujours cette ent&ecirc;te &agrave; la requ&ecirc;te</td>
</tr>
                    <tr>
<td><span class="new_code">setMaximumRedirects($max)</span></td><td>S'arr&ecirc;te apr&egrave;s autant de redirections</td>
</tr>
                    <tr>
<td><span class="new_code">setConnectionTimeout($timeout)</span></td><td>Termine la connexion apr&egrave;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&ecirc;tes &agrave; travers ce proxy d'URL</td>
</tr>
                </tbody>
</table>
            </p>
        
    </div>
<div class="copyright">
            Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004
        </div>
</body>
</html>