source: trunk/server/www/vendors/simpletest/docs/fr/mock_objects_documentation.html @ 6

Last change on this file since 6 was 6, checked in by sander, 11 years ago

Added SimpleTest? test framework

File size: 35.0 KB
Line 
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>Documentation SimpleTest : les objets fantaise</title>
5<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
6</head>
7<body>
8<div class="menu_back"><div class="menu">
9<a href="index.html">SimpleTest</a>
10                |
11                <a href="overview.html">Overview</a>
12                |
13                <a href="unit_test_documentation.html">Unit tester</a>
14                |
15                <a href="group_test_documentation.html">Group tests</a>
16                |
17                <a href="mock_objects_documentation.html">Mock objects</a>
18                |
19                <a href="partial_mocks_documentation.html">Partial mocks</a>
20                |
21                <a href="reporter_documentation.html">Reporting</a>
22                |
23                <a href="expectation_documentation.html">Expectations</a>
24                |
25                <a href="web_tester_documentation.html">Web tester</a>
26                |
27                <a href="form_testing_documentation.html">Testing forms</a>
28                |
29                <a href="authentication_documentation.html">Authentication</a>
30                |
31                <a href="browser_documentation.html">Scriptable browser</a>
32</div></div>
33<h1>Documentation sur les objets fantaisie</h1>
34        This page...
35        <ul>
36<li>
37            <a href="#quoi">Que sont les objets fantaisie ?</a>
38        </li>
39<li>
40            <a href="#creation">Créer des objets fantaisie</a>.
41        </li>
42<li>
43            <a href="#bouchon">L'objet fantaisie - acteur</a> ou bouchon.
44        </li>
45<li>
46            <a href="#attentes">L'objet fantaisie - critique</a> avec des attentes.
47        </li>
48<li>
49            <a href="#approches">D'autres approches</a>
50            y compris des librairies d'objets fantaisie.
51        </li>
52<li>
53            Utiliser les objets fantaisie avec
54            <a href="#autres_testeurs">d'autres testeurs unitaires</a>.
55        </li>
56</ul>
57<div class="content">
58        <p><a class="target" name="quoi"><h2>Que sont les objets fantaisie ?</h2></a></p>
59            <p>
60                Les objets fantaisie - ou "mock objects" en anglais -
61                ont deux rÃŽles pendant un scénario de test : acteur et critique.
62            </p>
63            <p>
64                Le comportement d'acteur est celui de simuler
65                des objets difficiles à initialiser ou trop consommateurs
66                en temps pendant un test.
67                Le cas classique est celui de la connexion à une base de données.
68                Mettre sur pied une base de données de test au lancement
69                de chaque test ralentirait considérablement les tests
70                et en plus exigerait l'installation d'un moteur
71                de base de données ainsi que des données sur la machine de test.
72                Si nous pouvons simuler la connexion
73                et renvoyer des données à notre guise
74                alors non seulement nous gagnons en pragmatisme
75                sur les tests mais en sus nous pouvons nourrir
76                notre base avec des données falsifiées
77                et voir comment il répond. Nous pouvons
78                simuler une base de données en suspens ou
79                d'autres cas extrêmes sans avoir à créer
80                une véritable panne de base de données.
81                En d'autres termes nous pouvons gagner
82                en contrÃŽle sur l'environnement de test.
83            </p>
84            <p>
85                Si les objets fantaisie ne se comportaient que comme
86                des acteurs alors on les connaîtrait sous le nom de
87                <a href="server_stubs_documentation.html">bouchons serveur</a>.
88            </p>
89            <p>
90                Cependant non seulement les objets fantaisie jouent
91                un rÃŽle (en fournissant à la demande les valeurs requises)
92                mais en plus ils sont aussi sensibles aux messages qui
93                leur sont envoyés (par le biais d'attentes).
94                En posant les paramÚtres attendus d'une méthode
95                ils agissent comme des gardiens :
96                un appel sur eux doit être réalisé correctement.
97                Si les attentes ne sont pas atteintes ils nous épargnent
98                l'effort de l'écriture d'une assertion de test avec
99                échec en réalisant cette tâche à notre place.
100                Dans le cas d'une connexion à une base de données
101                imaginaire ils peuvent tester si la requête, disons SQL,
102                a bien été formé par l'objet qui utilise cette connexion.
103                Mettez-les sur pied avec des attentes assez précises
104                et vous verrez que vous n'aurez presque plus d'assertion à écrire manuellement.
105            </p>
106       
107        <p><a class="target" name="creation"><h2>Créer des objets fantaisie</h2></a></p>
108            <p>
109                Comme pour la création des bouchons serveur, tout ce dont
110                nous avons besoin c'est d'un classe existante.
111                La fameuse connexion à une base de données qui ressemblerait à...
112<pre>
113<strong>class DatabaseConnection {
114    function DatabaseConnection() {
115    }
116   
117    function query() {
118    }
119   
120    function selectQuery() {
121    }
122}</strong>
123</pre>
124                Cette classe n'a pas encore besoin d'être implémentée.
125                Pour en créer sa version fantaisie nous devons juste
126                inclure la librairie d'objet fantaisie puis lancer le générateur...
127<pre>
128<strong>require_once('simpletest/unit_tester.php');
129require_once('simpletest/mock_objects.php');
130require_once('database_connection.php');
131
132Mock::generate('DatabaseConnection');</strong>
133</pre>
134                Ceci génÚre une classe clone appelée <span class="new_code">MockDatabaseConnection</span>.
135                Nous pouvons désormais créer des instances de
136                cette nouvelle classe à l'intérieur même de notre scénario de test...
137<pre>
138require_once('simpletest/unit_tester.php');
139require_once('simpletest/mock_objects.php');
140require_once('database_connection.php');
141
142Mock::generate('DatabaseConnection');
143<strong>
144class MyTestCase extends UnitTestCase {
145   
146    function testSomething() {
147        $connection = &amp;new MockDatabaseConnection($this);
148    }
149}</strong>
150</pre>
151                Contrairement aux bouchons, le constructeur
152                d'une classe fantaisie a besoin d'une référence au scénario
153                de test pour pouvoir transmettre les succÚs
154                et les échecs pendant qu'il vérifie les attentes.
155                ConcrÚtement ça veut dire que les objets fantaisie
156                ne peuvent être utilisés qu'au sein d'un scénario de test.
157                Malgré tout, cette puissance supplémentaire implique
158                que les bouchons ne sont que rarement utilisés
159                si des objets fantaisie sont disponibles.
160            </p>
161       
162        <p><a class="target" name="bouchon"><h2>Objets fantaisie en action</h2></a></p>
163            <p>
164                La version fantaisie d'une classe contient
165                toutes les méthodes de l'originale.
166                De la sorte une opération comme
167                <span class="new_code">$connection-&gt;query()</span>
168                est encore possible.
169                Tout comme avec les bouchons, nous pouvons remplacer
170                la valeur nulle renvoyée par défaut...
171<pre>
172<strong>$connection-&gt;setReturnValue('query', 37);</strong>
173</pre>
174                Désormais à chaque appel de
175                <span class="new_code">$connection-&gt;query()</span>
176                nous recevons comme résultat 37.
177                Tout comme avec les bouchons nous pouvons utiliser
178                des jokers et surcharger le paramÚtre joker.
179                Nous pouvons aussi ajouter des méthodes supplémentaires
180                à l'objet fantaisie lors de sa génération
181                et lui choisir un nom de classe qui lui soit propre...
182<pre>
183<strong>Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));</strong>
184</pre>
185                Ici l'objet fantaisie se comportera comme
186                si <span class="new_code">setOptions()</span> existait dans la classe originale.
187                C'est pratique si une classe a utilisé le mécanisme
188                <span class="new_code">overload()</span> de PHP pour ajouter des méthodes dynamiques.
189                Vous pouvez créer des fantaisies spéciales pour simuler cette situation.
190            </p>
191            <p>
192                Tous les modÚles disponibles avec les bouchons serveur
193                le sont également avec les objets fantaisie...
194<pre>
195class Iterator {
196    function Iterator() {
197    }
198   
199    function next() {
200    }
201}
202</pre>
203                Une nouvelle fois, supposons que cet itérateur
204                ne retourne que du texte jusqu'au moment où il atteint
205                son terme, quand il renvoie <span class="new_code">false</span>.
206                Nous pouvons le simuler avec...
207<pre>
208Mock::generate('Iterator');
209
210class IteratorTest extends UnitTestCase() {
211   
212    function testASequence() {<strong>
213        $iterator = &amp;new MockIterator($this);
214        $iterator-&gt;setReturnValue('next', false);
215        $iterator-&gt;setReturnValueAt(0, 'next', 'First string');
216        $iterator-&gt;setReturnValueAt(1, 'next', 'Second string');</strong>
217        ...
218    }
219}
220</pre>
221                Au moment du premier appel à <span class="new_code">next()</span>
222                sur l'itérateur fantaisie il renverra tout d'abord
223                "First string", puis ce sera au tour de
224                "Second string" au deuxiÚme appel
225                et ensuite pour tout appel suivant <span class="new_code">false</span>
226                sera renvoyé.
227                Ces valeurs renvoyées successivement sont prioritaires
228                sur la valeur constante retournée.
229                Cette derniÚre est un genre de valeur par défaut si vous voulez.
230            </p>
231            <p>
232                Reprenons aussi le conteneur d'information bouchonné
233                avec des pairs clef / valeur...
234<pre>
235class Configuration {
236    function Configuration() {
237    }
238   
239    function getValue($key) {
240    }
241}
242</pre>
243                Il s'agit là d'une situation classique
244                d'utilisation d'objets fantaisie étant donné
245                que la configuration peut varier grandement de machine à machine :
246                ça contraint fortement la fiabilité de nos tests
247                si nous l'utilisons directement.
248                Le problÚme est que toutes les données nous parviennent
249                à travers la méthode <span class="new_code">getValue()</span>
250                et que nous voulons des résultats différents pour des clefs différentes.
251                Heureusement les objets fantaisie ont un systÚme de filtrage...
252<pre>
253<strong>$config = &amp;new MockConfiguration($this);
254$config-&gt;setReturnValue('getValue', 'primary', array('db_host'));
255$config-&gt;setReturnValue('getValue', 'admin', array('db_user'));
256$config-&gt;setReturnValue('getValue', 'secret', array('db_password'));</strong>
257</pre>
258                Le paramÚtre en plus est une liste d'arguments
259                à faire correspondre. Dans ce cas nous essayons
260                de faire correspondre un unique argument :
261                en l'occurrence la clef recherchée.
262                Maintenant que la méthode <span class="new_code">getValue()</span>
263                est invoquée sur l'objet fantaisie...
264<pre>
265$config-&gt;getValue('db_user')
266</pre>
267                ...elle renverra "admin".
268                Elle le trouve en essayant de faire correspondre
269                les arguments entrants dans sa liste
270                d'arguments sortants les uns aprÚs les autres
271                jusqu'au moment où une correspondance exacte est atteinte.
272            </p>
273            <p>
274                Il y a des fois où vous souhaitez
275                qu'un objet spécifique soit servi par la fantaisie
276                plutÃŽt qu'une copie.
277                De nouveau c'est identique au mécanisme des bouchons serveur...
278<pre>
279class Thing {
280}
281
282class Vector {
283    function Vector() {
284    }
285   
286    function get($index) {
287    }
288}
289</pre>
290                Dans ce cas vous pouvez placer une référence
291                dans la liste renvoyée par l'objet fantaisie...
292<pre>
293$thing = new Thing();<strong>
294$vector = &amp;new MockVector($this);
295$vector-&gt;setReturnReference('get', $thing, array(12));</strong>
296</pre>
297                Avec cet arrangement vous savez qu'à chaque appel
298                de <span class="new_code">$vector-&gt;get(12)</span>
299                le même <span class="new_code">$thing</span> sera renvoyé.
300            </p>
301       
302        <p><a class="target" name="attentes"><h2>Objets fantaisie en critique</h2></a></p>
303            <p>
304                Même si les bouchons serveur vous isolent
305                du désordre du monde réel, il ne s'agit là que
306                de la moitié du bénéfice potentiel.
307                Vous pouvez avoir une classe de test recevant
308                les messages ad hoc, mais est-ce que votre nouvelle classe
309                renvoie bien les bons ?
310                Le tester peut devenir cafouillis sans une librairie d'objets fantaisie.
311            </p>
312            <p>
313                Pour l'exemple, prenons une classe <span class="new_code">SessionPool</span>
314                à laquelle nous allons ajouter une fonction de log.
315                PlutÃŽt que de complexifier la classe originale,
316                nous souhaitons ajouter ce comportement avec un décorateur (GOF).
317                Pour l'instant le code de <span class="new_code">SessionPool</span> ressemble à...
318<pre>
319<strong>class SessionPool {
320    function SessionPool() {
321        ...
322    }
323   
324    function &amp;findSession($cookie) {
325        ...
326    }
327    ...
328}
329
330class Session {
331    ...
332}</strong>
333
334</pre>
335                Alors que pour notre code de log, nous avons...
336<pre><strong>
337class Log {
338    function Log() {
339        ...
340    }
341   
342    function message() {
343        ...
344    }
345}
346
347class LoggingSessionPool {
348    function LoggingSessionPool(&amp;$session_pool, &amp;$log) {
349        ...
350    }
351   
352    function &amp;findSession($cookie) {
353        ...
354    }
355    ...
356}</strong>
357</pre>
358                Dans tout ceci, la seule classe à tester est
359                <span class="new_code">LoggingSessionPool</span>. En particulier,
360                nous voulons vérifier que la méthode <span class="new_code">findSession()</span>
361                est appelée avec le bon identifiant de session au sein du cookie
362                et qu'elle renvoie bien le message "Starting session $cookie"
363                au loggueur.
364            </p>
365            <p>
366                Bien que nous ne testions que quelques lignes
367                de code de production, voici la liste des choses
368                à faire dans un scénario de test conventionnel :
369                <ol>
370                    <li>Créer un objet de log.</li>
371                    <li>Indiquer le répertoire d'écriture du fichier de log.</li>
372                    <li>Modifier les droits sur le répertoire pour pouvoir y écrire le fichier.</li>
373                    <li>Créer un objet <span class="new_code">SessionPool</span>.</li>
374                    <li>Lancer une session, ce qui demande probablement pas mal de choses.</li>
375                    <li>Invoquer <span class="new_code">findSession()</span>.</li>
376                    <li>Lire le nouvel identifiant de session (en espérant qu'il existe un accesseur !).</li>
377                    <li>Lever une assertion de test pour vérifier que cet identifiant correspond bien au cookie.</li>
378                    <li>Lire la derniÚre ligne du fichier de log.</li>
379                    <li>Supprimer avec une (ou plusieurs) expression rationnelle les timestamps de log en trop, etc.</li>
380                    <li>Vérifier que le message de session est bien dans le texte.</li>
381                </ol>
382                Pas étonnant que les développeurs détestent
383                écrire des tests quand ils sont aussi ingrats.
384                Pour rendre les choses encore pire, à chaque fois que
385                le format de log change ou bien que la méthode de création
386                des sessions change, nous devons réécrire une partie
387                des tests alors même qu'ils ne testent pas ces parties
388                du systÚme. Nous sommes en train de préparer
389                le cauchemar pour les développeurs de ces autres classes.
390            </p>
391            <p>
392                A la place, voici la méthode complÚte pour le test
393                avec un peu de magie via les objets fantaisie...
394<pre>
395Mock::generate('Session');
396Mock::generate('SessionPool');
397Mock::generate('Log');
398
399class LoggingSessionPoolTest extends UnitTestCase {
400    ...
401    function testFindSessionLogging() {<strong>
402        $session = &amp;new MockSession($this);
403        $pool = &amp;new MockSessionPool($this);
404        $pool-&gt;setReturnReference('findSession', $session);
405        $pool-&gt;expectOnce('findSession', array('abc'));
406       
407        $log = &amp;new MockLog($this);
408        $log-&gt;expectOnce('message', array('Starting session abc'));
409       
410        $logging_pool = &amp;new LoggingSessionPool($pool, $log);
411        $this-&gt;assertReference($logging_pool-&gt;findSession('abc'), $session);
412        $pool-&gt;tally();
413        $log-&gt;tally();</strong>
414    }
415}
416</pre>
417                Commençons par écrire une session simulacre.
418                Pas la peine d'être trop pointilleux avec
419                celle-ci puisque la vérification de la session
420                désirée est effectuée ailleurs. Nous avons
421                juste besoin de vérifier qu'il s'agit de
422                la même que celle qui vient du groupe commun des sessions.
423            </p>
424            <p>
425                <span class="new_code">findSession()</span> est un méthode fabrique
426                dont la simulation est décrite <a href="#stub">plus haut</a>.
427                Le point de départ vient avec le premier appel
428                <span class="new_code">expectOnce()</span>. Cette ligne indique
429                qu'à chaque fois que <span class="new_code">findSession()</span>
430                est invoqué sur l'objet fantaisie, il vérifiera
431                les arguments entrant. S'il ne reçoit
432                que la chaîne "abc" en tant qu'argument
433                alors un succÚs est envoyé au testeur unitaire,
434                sinon c'est un échec qui est généré.
435                Il s'agit là de la partie qui teste si nous avons bien
436                la bonne session. La liste des arguments suit
437                une format identique à celui qui précise les valeurs renvoyées.
438                Vous pouvez avoir des jokers et des séquences
439                et l'ordre de l'évaluation restera le même.
440            </p>
441            <p>
442                Si l'appel n'est jamais effectué alors n'est généré
443                ni le succÚs, ni l'échec. Pour contourner cette limitation,
444                nous devons dire à l'objet fantaisie que le test est terminé :
445                il pourra alors décider si les attentes ont été répondues.
446                L'assertion du testeur unitaire de ceci est déclenchée
447                par l'appel <span class="new_code">tally()</span> Ã  la fin du test.
448            </p>
449            <p>
450                Nous utilisons le même modÚle pour mettre sur pied
451                le loggueur fantaisie. Nous lui indiquons que <span class="new_code">message()</span>
452                devrait être invoqué une fois et une fois seulement
453                avec l'argument "Starting session abc".
454                En testant les arguments d'appel, plutÃŽt que ceux de sortie du loggueur,
455                nous isolons le test de tout modification dans le loggueur.
456            </p>
457            <p>
458                Nous commençons le lancement nos tests à la création
459                du nouveau <span class="new_code">LoggingSessionPool</span>
460                et nous l'alimentons avec nos objets fantaisie juste créés.
461                Désormais tout est sous contrÃŽle. Au final nous confirmons
462                que le <span class="new_code">$session</span> donné au décorateur est bien
463                celui reçu et prions les objets fantaisie de lancer leurs
464                tests de comptage d'appel interne avec les appels <span class="new_code">tally()</span>.
465            </p>
466            <p>
467                Il y a encore pas mal de code de test, mais ce code est trÚs strict.
468                S'il vous semble encore terrifiant il l'est bien moins
469                que si nous avions essayé sans les objets fantaisie
470                et ce test en particulier, interactions plutÃŽt que résultat,
471                est toujours plus difficile à mettre en place.
472                Le plus souvent vous aurez besoin de tester des situations
473                plus complexes sans ce niveau ni cette précision.
474                En outre une partie peut être remaniée avec la méthode
475                de scénario de test <span class="new_code">setUp()</span>.
476            </p>
477            <p>
478                Voici la liste complÚte des attentes que vous pouvez
479                placer sur un objet fantaisie avec
480                <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a>...
481                <table>
482<thead>
483                    <tr>
484<th>Attente</th>
485<th>Nécessite <span class="new_code">tally()</span>
486</th>
487</tr>
488                    </thead>
489<tbody>
490<tr>
491                        <td><span class="new_code">expectArguments($method, $args)</span></td>
492                        <td style="text-align: center">Non</td>
493                    </tr>
494                    <tr>
495                        <td><span class="new_code">expectArgumentsAt($timing, $method, $args)</span></td>
496                        <td style="text-align: center">Non</td>
497                    </tr>
498                    <tr>
499                        <td><span class="new_code">expectCallCount($method, $count)</span></td>
500                        <td style="text-align: center">Oui</td>
501                    </tr>
502                    <tr>
503                        <td><span class="new_code">expectMaximumCallCount($method, $count)</span></td>
504                        <td style="text-align: center">Non</td>
505                    </tr>
506                    <tr>
507                        <td><span class="new_code">expectMinimumCallCount($method, $count)</span></td>
508                        <td style="text-align: center">Oui</td>
509                    </tr>
510                    <tr>
511                        <td><span class="new_code">expectNever($method)</span></td>
512                        <td style="text-align: center">Non</td>
513                    </tr>
514                    <tr>
515                        <td><span class="new_code">expectOnce($method, $args)</span></td>
516                        <td style="text-align: center">Oui</td>
517                    </tr>
518                    <tr>
519                        <td><span class="new_code">expectAtLeastOnce($method, $args)</span></td>
520                        <td style="text-align: center">Oui</td>
521                    </tr>
522                </tbody>
523</table>
524                Où les paramÚtres sont...
525                <dl>
526                    <dt class="new_code">$method</dt>
527                    <dd>Le nom de la méthode, sous la forme d'une chaîne,
528                    à laquelle la condition doit être appliquée.</dd>
529                    <dt class="new_code">$args</dt>
530                    <dd>
531                        Les arguments sous la forme d'une liste.
532                        Les jokers peuvent être inclus de la même maniÚre
533                        qu'avec <span class="new_code">setReturn()</span>.
534                        Cet argument est optionnel pour <span class="new_code">expectOnce()</span>
535                        et <span class="new_code">expectAtLeastOnce()</span>.
536                    </dd>
537                    <dt class="new_code">$timing</dt>
538                    <dd>
539                        Le seul point dans le temps pour tester
540                        la condition. Le premier appel commence à zéro.
541                    </dd>
542                    <dt class="new_code">$count</dt>
543                    <dd>Le nombre d'appels attendu.</dd>
544                </dl>
545                La méthode <span class="new_code">expectMaximumCallCount()</span>
546                est légÚrement différente dans le sens où elle ne pourra
547                générer qu'un échec. Elle reste silencieuse
548                si la limite n'est jamais atteinte.
549            </p>
550            <p>
551                Par ailleurs si vous avez just un appel dans votre test,
552                vérifiez bien que vous utiliser
553                <span class="new_code">expectOnce</span>.<br>
554                Utiliser <span class="new_code">$mocked-&gt;expectAt(0, 'method', 'args);</span>
555                tout seul ne sera pas pris en compte :
556                la vérification des arguments et le comptage total
557                sont pour l'instant encore indépendant.
558            </p>
559            <p>
560                Comme avec les assertions dans les scénarios de test,
561                toutes ces attentes peuvent accepter une surcharge de
562                message sous la forme d'un paramÚtre supplémentaire.
563                Par ailleurs le message d'échec original peut être inclus
564                dans le résultat avec "%s".
565            </p>
566       
567        <p><a class="target" name="approches"><h2>D'autres approches</h2></a></p>
568            <p>
569                Il existe trois approches pour créer des objets
570                fantaisie en comprenant celle utilisée par SimpleTest.
571                Les coder à la main en utilisant une classe de base,
572                les générer dans un fichier ou les générer dynamiquement à la volée.
573            </p>
574            <p>
575                Les objets fantaisie générés avec
576                <a href="simple_test.html">SimpleTest</a> sont dynamiques.
577                Ils sont créés à l'exécution dans la mémoire,
578                grâce à <span class="new_code">eval()</span>, plutÃŽt qu'écrits dans un fichier.
579                Cette opération les rend facile à créer,
580                en une seule ligne, surtout par rapport à leur création
581                à la main dans une hiérarchie de classe parallÚle.
582                Le problÚme avec ce comportement tient généralement
583                dans la mise en place des tests proprement dits.
584                Si les objets originaux changent les versions fantaisie
585                sur lesquels reposent les tests, une désynchronisation peut subvenir.
586                Cela peut aussi arriver avec l'approche en hiérarchie parallÚle,
587                mais c'est détecté beaucoup plus vite.
588            </p>
589            <p>
590                Bien sûr, la solution est d'ajouter de véritables tests d'intégration.
591                Vous n'en avez pas besoin de beaucoup
592                et le cÃŽté pratique des objets fantaisie fait plus
593                que compenser la petite dose de test supplémentaire.
594                Vous ne pouvez pas avoir confiance dans du code qui
595                ne serait testé que par des objets fantaisie.
596            </p>
597            <p>
598                Si vous restez déterminé de construire des librairies
599                statiques d'objets fantaisie parce que vous souhaitez
600                émuler un comportement trÚs spécifique,
601                vous pouvez y parvenir grâce au générateur de classe de SimpleTest.
602                Dans votre fichier librairie, par exemple
603                <em>mocks/connection.php</em> pour une connexion à une base de données,
604                créer un objet fantaisie et provoquer l'héritage
605                pour hériter pour surcharger des méthodes spéciales
606                ou ajouter des préréglages...
607<pre>
608&lt;?php
609    require_once('simpletest/mock_objects.php');
610    require_once('../classes/connection.php');
611<strong>
612    Mock::generate('Connection', 'BasicMockConnection');
613    class MockConnection extends BasicMockConnection {
614        function MockConnection(&amp;$test, $wildcard = '*') {
615            $this-&gt;BasicMockConnection($test, $wildcard);
616            $this-&gt;setReturn('query', false);
617        }
618    }</strong>
619?&gt;
620</pre>
621                L'appel <span class="new_code">generate</span> dit au générateur de classe
622                d'en créer une appelée <span class="new_code">BasicMockConnection</span>
623                plutÃŽt que la plus courante <span class="new_code">MockConnection</span>.
624                Ensuite nous héritons à partir de celle-ci pour obtenir
625                notre version de <span class="new_code">MockConnection</span>.
626                En interceptant de cette maniÚre nous pouvons ajouter
627                un comportement, ici transformer la valeur par défaut de
628                <span class="new_code">query()</span> en "false".
629                En utilisant le nom par défaut nous garantissons
630                que le générateur de classe fantaisie n'en recréera
631                pas une autre différente si il est invoqué ailleurs
632                dans les tests. Il ne créera jamais de classe
633                si elle existe déjà. Aussi longtemps que le fichier
634                ci-dessus est inclus avant alors tous les tests qui
635                généraient <span class="new_code">MockConnection</span> devraient
636                utiliser notre version à présent. Par contre si
637                nous avons une erreur dans l'ordre et que la librairie
638                de fantaisie en crée une d'abord alors la création
639                de la classe échouera tout simplement.
640            </p>
641            <p>
642                Utiliser cette astuce si vous vous trouvez avec beaucoup
643                de comportement en commun sur les objets fantaisie
644                ou si vous avez de fréquents problÚmes d'intégration
645                plus tard dans les étapes de test.
646            </p>
647       
648        <p><a class="target" name="autres_testeurs"><h2>Je pense que SimpleTest pue !</h2></a></p>
649            <p>
650                Mais au moment d'écrire ces lignes c'est le seul
651                à gérer les objets fantaisie, donc vous êtes bloqué avec lui ?
652            </p>
653            <p>
654                Non, pas du tout.
655                <a href="simple_test.html">SimpleTest</a> est une boîte à outils
656                et parmi ceux-ci on trouve les objets fantaisie
657                qui peuvent être utilisés indépendamment.
658                Supposons que vous avez votre propre testeur unitaire favori
659                et que tous vos tests actuels l'utilisent.
660                Prétendez que vous avez appelé votre tester unitaire PHPUnit
661                (c'est ce que tout le monde a fait) et que la classe principale
662                de test ressemble à...
663<pre>
664class PHPUnit {
665    function PHPUnit() {
666    }
667   
668    function assertion($message, $assertion) {
669    }
670    ...
671}
672</pre>
673                La seule chose que la méthode <span class="new_code">assertion()</span> réalise,
674                c'est de préparer une sortie embellie alors le paramÚtre boolien
675                de l'assertion sert à déterminer s'il s'agit d'une erreur ou d'un succÚs.
676                Supposons qu'elle est utilisée de la maniÚre suivante...
677<pre>
678$unit_test = new PHPUnit();
679$unit_test&gt;assertion('I hope this file exists', file_exists('my_file'));
680</pre>
681                Comment utiliser les objets fantaisie avec ceci ?
682            </p>
683            <p>
684                Il y a une méthode protégée sur la classe de base
685                des objets fantaisie : elle s'appelle <span class="new_code">_assertTrue()</span>.
686                En surchargeant cette méthode nous pouvons utiliser
687                notre propre format d'assertion.
688                Nous commençons avec une sous-classe, dans <em>my_mock.php</em>...
689<pre>
690<strong>&lt;?php
691    require_once('simpletest/mock_objects.php');
692   
693    class MyMock extends SimpleMock() {
694        function MyMock(&amp;$test, $wildcard) {
695            $this-&gt;SimpleMock($test, $wildcard);
696        }
697       
698        function _assertTrue($assertion, $message) {
699            $test = &amp;$this-&gt;getTest();
700            $test-&gt;assertion($message, $assertion);
701        }
702    }
703?&gt;</strong>
704</pre>
705                Maintenant une instance de <span class="new_code">MyMock</span>
706                créera un objet qui parle le même langage que votre testeur.
707                Bien sûr le truc c'est que nous créons jamais un tel objet :
708                le générateur s'en chargera. Nous avons juste besoin
709                d'une ligne de code supplémentaire pour dire au générateur
710                d'utiliser vos nouveaux objets fantaisie...
711<pre>
712&lt;?php
713    require_once('simpletst/mock_objects.php');
714   
715    class MyMock extends SimpleMock() {
716        function MyMock($test, $wildcard) {
717            $this-&gt;SimpleMock(&amp;$test, $wildcard);
718        }
719       
720        function _assertTrue($assertion, $message , &amp;$test) {
721            $test-&gt;assertion($message, $assertion);
722        }
723    }<strong>
724    SimpleTestOptions::setMockBaseClass('MyMock');</strong>
725?&gt;
726</pre>
727                A partir de maintenant vous avez juste à inclure
728                <em>my_mock.php</em> Ã  la place de la version par défaut
729                <em>simple_mock.php</em> et vous pouvez introduire
730                des objets fantaisie dans votre suite de tests existants.
731            </p>
732       
733    </div>
734        References and related information...
735        <ul>
736<li>
737            L'article originel sur
738            <a href="http://www.mockobjects.com/">les objets fantaisie</a>.
739        </li>
740<li>
741            La page du projet SimpleTest sur
742            <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
743        </li>
744<li>
745            La page d'accueil de SimpleTest sur
746            <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
747        </li>
748</ul>
749<div class="menu_back"><div class="menu">
750<a href="index.html">SimpleTest</a>
751                |
752                <a href="overview.html">Overview</a>
753                |
754                <a href="unit_test_documentation.html">Unit tester</a>
755                |
756                <a href="group_test_documentation.html">Group tests</a>
757                |
758                <a href="mock_objects_documentation.html">Mock objects</a>
759                |
760                <a href="partial_mocks_documentation.html">Partial mocks</a>
761                |
762                <a href="reporter_documentation.html">Reporting</a>
763                |
764                <a href="expectation_documentation.html">Expectations</a>
765                |
766                <a href="web_tester_documentation.html">Web tester</a>
767                |
768                <a href="form_testing_documentation.html">Testing forms</a>
769                |
770                <a href="authentication_documentation.html">Authentication</a>
771                |
772                <a href="browser_documentation.html">Scriptable browser</a>
773</div></div>
774<div class="copyright">
775            Copyright<br>Marcus Baker 2006
776        </div>
777</body>
778</html>
Note: See TracBrowser for help on using the repository browser.