unit_test_documentation.html 15 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
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Documenation SimpleTest pour les tests de r&eacute;gression en PHP</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 les tests unitaires en PHP</h1>
<div class="content">
        <p>
<a class="target" name="unitaire">
<h2>Sc&eacute;narios de tests unitaires</h2>
</a>
</p>
            <p>
                Le coeur du syst&egrave;me est un framework de test de r&eacute;gression construit autour des sc&eacute;narios de test. Un exemple de sc&eacute;nario de test ressemble &agrave;...
<pre>
<strong>class FileTestCase extends UnitTestCase {
}</strong>
</pre>
                Si aucun nom de test n'est fourni au moment de la liaison avec le constructeur alors le nom de la classe sera utilis&eacute;. Il s'agit du nom qui sera affich&eacute; dans les r&eacute;sultats du test.
            </p>
            <p>
                Les v&eacute;ritables tests sont ajout&eacute;s en tant que m&eacute;thode dans le sc&eacute;nario de test dont le nom par d&eacute;faut commence par la cha&icirc;ne "test" et quand le sc&eacute;nario de test est appel&eacute; toutes les m&eacute;thodes de ce type sont ex&eacute;cut&eacute;es dans l'ordre utilis&eacute; par l'introspection de PHP pour les trouver. Peuvent &ecirc;tre ajout&eacute;es autant de m&eacute;thodes de test que n&eacute;cessaires. Par exemple...
<pre>
require_once('../classes/writer.php');

class FileTestCase extends UnitTestCase {
    function FileTestCase() {
        $this-&gt;UnitTestCase('File test');
    }<strong>
    
    function setUp() {
        @unlink('../temp/test.txt');
    }
    
    function tearDown() {
        @unlink('../temp/test.txt');
    }
    
    function testCreation() {
        $writer = &amp;new FileWriter('../temp/test.txt');
        $writer-&gt;write('Hello');
        $this-&gt;assertTrue(file_exists('../temp/test.txt'), 'File created');
    }</strong>
}
</pre>
                Le constructeur est optionnel et souvent omis. Sans nom, le nom de la classe est utilis&eacute; comme nom pour le sc&eacute;nario de test.
            </p>
            <p>
                Notre unique m&eacute;thode de test pour le moment est <span class="new_code">testCreation()</span> o&ugrave; nous v&eacute;rifions qu'un fichier a bien &eacute;t&eacute; cr&eacute;&eacute; par notre objet <span class="new_code">Writer</span>. Nous pourrions avoir mis le code <span class="new_code">unlink()</span> dans cette m&eacute;thode, mais en la pla&ccedil;ant dans <span class="new_code">setUp()</span> et <span class="new_code">tearDown()</span> nous pouvons l'utiliser pour nos autres m&eacute;thodes de test que nous ajouterons.
            </p>
            <p>
                La m&eacute;thode <span class="new_code">setUp()</span> est lanc&eacute; juste avant chaque m&eacute;thode de test. <span class="new_code">tearDown()</span> est lanc&eacute; apr&egrave;s chaque m&eacute;thode de test.
            </p>
            <p>
                Vous pouvez placer une initialisation de sc&eacute;nario de test dans le constructeur afin qu'elle soit lanc&eacute;e pour toutes les m&eacute;thodes dans le sc&eacute;nario de test mais dans un tel cas vous vous exposeriez &agrave; des interf&eacute;rences. Cette fa&ccedil;on de faire est l&eacute;g&egrave;rement moins rapide, mais elle est plus s&ucirc;re. Notez que si vous arrivez avec des notions de JUnit, il ne s'agit pas du comportement auquel vous &ecirc;tes habitu&eacute;s. Bizarrement JUnit re-instancie le sc&eacute;nario de test pour chaque m&eacute;thode de test pour se pr&eacute;venir d'une telle interf&eacute;rence. SimpleTest demande &agrave; l'utilisateur final d'utiliser <span class="new_code">setUp()</span>, mais fournit aux codeurs de biblioth&egrave;que d'autres crochets.
            </p>
            <p>
                Pour rapporter les r&eacute;sultats de test, le passage par une classe d'affichage - notifi&eacute;e par les diff&eacute;rentes m&eacute;thodes de type <span class="new_code">assert...()</span> - est utilis&eacute;e. En voici la liste compl&egrave;te pour la classe <span class="new_code">UnitTestCase</span>, celle par d&eacute;faut dans SimpleTest...
            <table>
<tbody>
                <tr>
<td><span class="new_code">assertTrue($x)</span></td><td>Echoue si $x est faux</td>
</tr>
                <tr>
<td><span class="new_code">assertFalse($x)</span></td><td>Echoue si $x est vrai</td>
</tr>
                <tr>
<td><span class="new_code">assertNull($x)</span></td><td>Echoue si $x est initialis&eacute;</td>
</tr>
                <tr>
<td><span class="new_code">assertNotNull($x)</span></td><td>Echoue si $x n'est pas initialis&eacute;</td>
</tr>
                <tr>
<td><span class="new_code">assertIsA($x, $t)</span></td><td>Echoue si $x n'est pas de la classe ou du type $t</td>
</tr>
                <tr>
<td><span class="new_code">assertEqual($x, $y)</span></td><td>Echoue si $x == $y est faux</td>
</tr>
                <tr>
<td><span class="new_code">assertNotEqual($x, $y)</span></td><td>Echoue si $x == $y est vrai</td>
</tr>
                <tr>
<td><span class="new_code">assertIdentical($x, $y)</span></td><td>Echoue si $x === $y est faux</td>
</tr>
                <tr>
<td><span class="new_code">assertNotIdentical($x, $y)</span></td><td>Echoue si $x === $y est vrai</td>
</tr>
                <tr>
<td><span class="new_code">assertReference($x, $y)</span></td><td>Echoue sauf si $x et $y sont la m&ecirc;me variable</td>
</tr>
                <tr>
<td><span class="new_code">assertCopy($x, $y)</span></td><td>Echoue si $x et $y sont la m&ecirc;me variable</td>
</tr>
                <tr>
<td><span class="new_code">assertWantedPattern($p, $x)</span></td><td>Echoue sauf si l'expression rationnelle $p capture $x</td>
</tr>
                <tr>
<td><span class="new_code">assertNoUnwantedPattern($p, $x)</span></td><td>Echoue si l'expression rationnelle $p capture $x</td>
</tr>
                <tr>
<td><span class="new_code">assertNoErrors()</span></td><td>Echoue si une erreur PHP arrive</td>
</tr>
                <tr>
<td><span class="new_code">assertError($x)</span></td><td>Echoue si aucune erreur ou message incorrect de PHP n'arrive</td>
</tr>
            </tbody>
</table>
                Toutes les m&eacute;thodes d'assertion peuvent recevoir une description optionnelle : cette description sert pour &eacute;tiqueter le r&eacute;sultat.
                Sans elle, une message par d&eacute;faut est envoy&eacute;e &agrave; la place : il est g&eacute;n&eacute;ralement suffisant. Ce message par d&eacute;faut peut encore &ecirc;tre encadr&eacute; dans votre propre message si vous incluez "%s" dans la cha&icirc;ne. Toutes les assertions renvoient vrai / true en cas de succ&egrave;s et faux / false en cas d'&eacute;chec.
            </p>
            <p>
                D'autres exemples...
<pre>
<strong>$variable = null;
$this-&gt;assertNull($variable, 'Should be cleared');</strong>
</pre>
                ...passera et normalement n'affichera aucun message. Si vous avez <a href="http://www.lastcraft.com/display_subclass_tutorial.php">configur&eacute; le testeur pour afficher aussi les succ&egrave;s</a> alors le message sera affich&eacute; comme tel.
<pre>
<strong>$this-&gt;assertIdentical(0, false, 'Zero is not false [%s]');</strong>
</pre>
                Ceci &eacute;chouera &eacute;tant donn&eacute; qu'il effectue une v&eacute;rification sur le type en plus d'une comparaison sur les deux valeurs. La partie "%s" est remplac&eacute;e par le message d'erreur par d&eacute;faut qui aurait &eacute;t&eacute; affich&eacute; si nous n'avions pas fourni le n&ocirc;tre. Cela nous permet d'embo&icirc;ter les messages de test.
<pre>
<strong>$a = 1;
$b = $a;
$this-&gt;assertReference($a, $b);</strong>
</pre>
                &Eacute;chouera &eacute;tant donn&eacute; que la variable <span class="new_code">$b</span> est une copie de <span class="new_code">$a</span>.
<pre>
<strong>$this-&gt;assertWantedPattern('/hello/i', 'Hello world');</strong>
</pre>
                L&agrave;, &ccedil;a passe puisque la recherche est insensible &agrave; la casse et que donc <span class="new_code">hello</span> est bien rep&eacute;rable dans <span class="new_code">Hello world</span>.
<pre>
<strong>trigger_error('Disaster');
trigger_error('Catastrophe');
$this-&gt;assertError();
$this-&gt;assertError('Catastrophe');
$this-&gt;assertNoErrors();</strong>
</pre>
                Ici, il y a besoin d'une petite explication : toutes passent !
            </p>
            <p>
                Les erreurs PHP dans SimpleTest sont pi&eacute;g&eacute;es et plac&eacute;es dans une queue. Ici la premi&egrave;re v&eacute;rification d'erreur attrape le message "Disaster" sans v&eacute;rifier le texte et passe. R&eacute;sultat : l'erreur est supprim&eacute;e de la queue. La v&eacute;rification suivante teste non seulement l'existence de l'erreur mais aussi le texte qui correspond : un autre succ&egrave;s. D&eacute;sormais la queue est vide et le dernier test passe aussi. Si une autre erreur non v&eacute;rifi&eacute;e est encore dans la queue &agrave; la fin de notre m&eacute;thode de test alors une exception sera rapport&eacute;e dans le test. Notez que SimpleTest ne peut pas attraper les erreurs PHP &agrave; la compilation.
            </p>
            <p>
                Les sc&eacute;narios de test peuvent utiliser des m&eacute;thodes bien pratiques pour d&eacute;boguer le code ou pour &eacute;tendre la suite...
                <table>
<tbody>
                    <tr>
<td><span class="new_code">setUp()</span></td><td>Est lanc&eacute;e avant chaque m&eacute;thode de test</td>
</tr>
                    <tr>
<td><span class="new_code">tearDown()</span></td><td>Est lanc&eacute;e apr&egrave;s chaque m&eacute;thode de test</td>
</tr>
                    <tr>
<td><span class="new_code">pass()</span></td><td>Envoie un succ&egrave;s</td>
</tr>
                    <tr>
<td><span class="new_code">fail()</span></td><td>Envoie un &eacute;chec</td>
</tr>
                    <tr>
<td><span class="new_code">error()</span></td><td>Envoi un &eacute;v&egrave;nement exception</td>
</tr>
                    <tr>
<td><span class="new_code">sendMessage()</span></td><td>Envoie un message d'&eacute;tat aux syst&egrave;mes d'affichage qui le supporte</td>
</tr>
                    <tr>
<td><span class="new_code">signal($type, $payload)</span></td><td>Envoie un message d&eacute;fini par l'utilisateur au rapporteur du test</td>
</tr>
                    <tr>
<td><span class="new_code">dump($var)</span></td><td>Effectue un <span class="new_code">print_r()</span> format&eacute; pour du d&eacute;boguage rapide et grossier</td>
</tr>
                    <tr>
<td><span class="new_code">swallowErrors()</span></td><td>Vide les erreurs de la queue</td>
</tr>
                </tbody>
</table>
            </p>
        
        <p>
<a class="target" name="extension_unitaire">
<h2>Etendre les sc&eacute;narios de test</h2>
</a>
</p>
            <p>
                Bien s&ucirc;r des m&eacute;thodes suppl&eacute;mentaires de test peuvent &ecirc;tre ajout&eacute;es pour cr&eacute;er d'autres types de sc&eacute;nario de test afin d'&eacute;tendre le framework...
<pre>
require_once('simpletest/unit_tester.php');
<strong>
class FileTester extends UnitTestCase {
    function FileTester($name = false) {
        $this-&gt;UnitTestCase($name);
    }
    
    function assertFileExists($filename, $message = '%s') {
        $this-&gt;assertTrue(
                file_exists($filename),
                sprintf($message, 'File [$filename] existence check'));
    }</strong>
}
</pre>
                Ici la biblioth&egrave;que SimpleTest est localis&eacute;e dans un r&eacute;pertoire local appel&eacute; <em>simpletest</em>. Pensez &agrave; le modifier pour votre propre environnement.
            </p>
            <p>
                Ce nouveau sc&eacute;nario peut &ecirc;tre h&eacute;rit&eacute; exactement comme un sc&eacute;nario de test classique...
<pre>
class FileTestCase extends <strong>FileTester</strong> {
    
    function setUp() {
        @unlink('../temp/test.txt');
    }
    
    function tearDown() {
        @unlink('../temp/test.txt');
    }
    
    function testCreation() {
        $writer = &amp;new FileWriter('../temp/test.txt');
        $writer-&gt;write('Hello');<strong>
        $this-&gt;assertFileExists('../temp/test.txt');</strong>
    }
}
</pre>
            </p>
            <p>
                Si vous souhaitez un sc&eacute;nario de test sans toutes les assertions de <span class="new_code">UnitTestCase</span> mais uniquement avec les v&ocirc;tres propres, vous aurez besoin d'&eacute;tendre la classe <span class="new_code">SimpleTestCase</span> &agrave; la place. Elle se trouve dans <em>simple_test.php</em> en lieu et place de <em>unit_tester.php</em>. A consulter <a href="group_test_documentation.html">plus tard</a> si vous souhaitez incorporer les sc&eacute;narios d'autres testeurs unitaires dans votre suite de test.
            </p>
        
        <p>
<a class="target" name="lancement_unitaire">
<h2>Lancer un unique sc&eacute;nario de test</h2>
</a>
</p>
            <p>
                Ce n'est pas souvent qu'il faille lancer des sc&eacute;narios avec un unique test. Sauf lorsqu'il s'agit de s'arracher les cheveux sur un module &agrave; probl&egrave;me sans pour autant d&eacute;sorganiser la suite de test principale. Voici l'&eacute;chafaudage n&eacute;cessaire pour lancer un sc&eacute;nario de test solitaire...
<pre>
&lt;?php
    require_once('simpletest/unit_tester.php');<strong>
    require_once('simpletest/reporter.php');</strong>
    require_once('../classes/writer.php');

    class FileTestCase extends UnitTestCase {
        function FileTestCase() {
            $this-&gt;UnitTestCase('File test');
        }
    }<strong>
    
    $test = &amp;new FileTestCase();
    $test-&gt;run(new HtmlReporter());</strong>
?&gt;
</pre>
                Ce script sera lanc&eacute; tel que mais il n'y aura aucun succ&egrave;s ou &eacute;chec avant que des m&eacute;thodes de test soient ajout&eacute;es.
            </p>
        
    </div>
<div class="copyright">
            Copyright<br>Marcus Baker, Jason Sweat, Perrick Penet 2004
        </div>
</body>
</html>