aboutsummaryrefslogtreecommitdiff
path: root/vendors/simpletest/docs/fr/mock_objects_documentation.html
blob: c03ac611f1715825a7caf498450ee749fb8a56ee (plain)
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
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Documentation SimpleTest : les objets fantaise</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 les objets fantaisie</h1>
        This page...
        <ul>
<li>
            <a href="#quoi">Que sont les objets fantaisie ?</a>
        </li>
<li>
            <a href="#creation">Créer des objets fantaisie</a>.
        </li>
<li>
            <a href="#bouchon">L'objet fantaisie - acteur</a> ou bouchon.
        </li>
<li>
            <a href="#attentes">L'objet fantaisie - critique</a> avec des attentes.
        </li>
<li>
            <a href="#approches">D'autres approches</a>
            y compris des librairies d'objets fantaisie.
        </li>
<li>
            Utiliser les objets fantaisie avec
            <a href="#autres_testeurs">d'autres testeurs unitaires</a>.
        </li>
</ul>
<div class="content">
        <p><a class="target" name="quoi"><h2>Que sont les objets fantaisie ?</h2></a></p>
            <p>
                Les objets fantaisie - ou "mock objects" en anglais -
                ont deux rôles pendant un scénario de test : acteur et critique.
            </p>
            <p>
                Le comportement d'acteur est celui de simuler
                des objets difficiles à initialiser ou trop consommateurs
                en temps pendant un test.
                Le cas classique est celui de la connexion à une base de données.
                Mettre sur pied une base de données de test au lancement
                de chaque test ralentirait considérablement les tests
                et en plus exigerait l'installation d'un moteur
                de base de données ainsi que des données sur la machine de test.
                Si nous pouvons simuler la connexion
                et renvoyer des données à notre guise
                alors non seulement nous gagnons en pragmatisme
                sur les tests mais en sus nous pouvons nourrir
                notre base avec des données falsifiées
                et voir comment il répond. Nous pouvons
                simuler une base de données en suspens ou
                d'autres cas extrêmes sans avoir à créer
                une véritable panne de base de données.
                En d'autres termes nous pouvons gagner
                en contrôle sur l'environnement de test.
            </p>
            <p>
                Si les objets fantaisie ne se comportaient que comme
                des acteurs alors on les connaîtrait sous le nom de
                <a href="server_stubs_documentation.html">bouchons serveur</a>.
            </p>
            <p>
                Cependant non seulement les objets fantaisie jouent
                un rôle (en fournissant à la demande les valeurs requises)
                mais en plus ils sont aussi sensibles aux messages qui
                leur sont envoyés (par le biais d'attentes).
                En posant les paramètres attendus d'une méthode
                ils agissent comme des gardiens :
                un appel sur eux doit être réalisé correctement.
                Si les attentes ne sont pas atteintes ils nous épargnent
                l'effort de l'écriture d'une assertion de test avec
                échec en réalisant cette tâche à notre place.
                Dans le cas d'une connexion à une base de données
                imaginaire ils peuvent tester si la requête, disons SQL,
                a bien été formé par l'objet qui utilise cette connexion.
                Mettez-les sur pied avec des attentes assez précises
                et vous verrez que vous n'aurez presque plus d'assertion à écrire manuellement.
            </p>
        
        <p><a class="target" name="creation"><h2>Créer des objets fantaisie</h2></a></p>
            <p>
                Comme pour la création des bouchons serveur, tout ce dont
                nous avons besoin c'est d'un classe existante.
                La fameuse connexion à une base de données qui ressemblerait à...
<pre>
<strong>class DatabaseConnection {
    function DatabaseConnection() {
    }
    
    function query() {
    }
    
    function selectQuery() {
    }
}</strong>
</pre>
                Cette classe n'a pas encore besoin d'être implémentée.
                Pour en créer sa version fantaisie nous devons juste
                inclure la librairie d'objet fantaisie puis lancer le générateur...
<pre>
<strong>require_once('simpletest/unit_tester.php');
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');

Mock::generate('DatabaseConnection');</strong>
</pre>
                Ceci génère une classe clone appelée <span class="new_code">MockDatabaseConnection</span>.
                Nous pouvons désormais créer des instances de
                cette nouvelle classe à l'intérieur même de notre scénario de test...
<pre>
require_once('simpletest/unit_tester.php');
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');

Mock::generate('DatabaseConnection');
<strong>
class MyTestCase extends UnitTestCase {
    
    function testSomething() {
        $connection = &amp;new MockDatabaseConnection($this);
    }
}</strong>
</pre>
                Contrairement aux bouchons, le constructeur
                d'une classe fantaisie a besoin d'une référence au scénario
                de test pour pouvoir transmettre les succès
                et les échecs pendant qu'il vérifie les attentes.
                Concrètement ça veut dire que les objets fantaisie
                ne peuvent être utilisés qu'au sein d'un scénario de test.
                Malgré tout, cette puissance supplémentaire implique
                que les bouchons ne sont que rarement utilisés
                si des objets fantaisie sont disponibles.
            </p>
        
        <p><a class="target" name="bouchon"><h2>Objets fantaisie en action</h2></a></p>
            <p>
                La version fantaisie d'une classe contient
                toutes les méthodes de l'originale.
                De la sorte une opération comme
                <span class="new_code">$connection-&gt;query()</span>
                est encore possible.
                Tout comme avec les bouchons, nous pouvons remplacer
                la valeur nulle renvoyée par défaut...
<pre>
<strong>$connection-&gt;setReturnValue('query', 37);</strong>
</pre>
                Désormais à chaque appel de
                <span class="new_code">$connection-&gt;query()</span>
                nous recevons comme résultat 37.
                Tout comme avec les bouchons nous pouvons utiliser
                des jokers et surcharger le paramètre joker.
                Nous pouvons aussi ajouter des méthodes supplémentaires
                à l'objet fantaisie lors de sa génération
                et lui choisir un nom de classe qui lui soit propre...
<pre>
<strong>Mock::generate('DatabaseConnection', 'MyMockDatabaseConnection', array('setOptions'));</strong>
</pre>
                Ici l'objet fantaisie se comportera comme
                si <span class="new_code">setOptions()</span> existait dans la classe originale.
                C'est pratique si une classe a utilisé le mécanisme
                <span class="new_code">overload()</span> de PHP pour ajouter des méthodes dynamiques.
                Vous pouvez créer des fantaisies spéciales pour simuler cette situation.
            </p>
            <p>
                Tous les modèles disponibles avec les bouchons serveur
                le sont également avec les objets fantaisie...
<pre>
class Iterator {
    function Iterator() {
    }
    
    function next() {
    }
}
</pre>
                Une nouvelle fois, supposons que cet itérateur
                ne retourne que du texte jusqu'au moment où il atteint
                son terme, quand il renvoie <span class="new_code">false</span>.
                Nous pouvons le simuler avec...
<pre>
Mock::generate('Iterator');

class IteratorTest extends UnitTestCase() {
    
    function testASequence() {<strong>
        $iterator = &amp;new MockIterator($this);
        $iterator-&gt;setReturnValue('next', false);
        $iterator-&gt;setReturnValueAt(0, 'next', 'First string');
        $iterator-&gt;setReturnValueAt(1, 'next', 'Second string');</strong>
        ...
    }
}
</pre>
                Au moment du premier appel à <span class="new_code">next()</span>
                sur l'itérateur fantaisie il renverra tout d'abord
                "First string", puis ce sera au tour de
                "Second string" au deuxième appel
                et ensuite pour tout appel suivant <span class="new_code">false</span>
                sera renvoyé.
                Ces valeurs renvoyées successivement sont prioritaires
                sur la valeur constante retournée.
                Cette dernière est un genre de valeur par défaut si vous voulez.
            </p>
            <p>
                Reprenons aussi le conteneur d'information bouchonné
                avec des pairs clef / valeur...
<pre>
class Configuration {
    function Configuration() {
    }
    
    function getValue($key) {
    }
}
</pre>
                Il s'agit là d'une situation classique
                d'utilisation d'objets fantaisie étant donné
                que la configuration peut varier grandement de machine à machine :
                ça contraint fortement la fiabilité de nos tests
                si nous l'utilisons directement.
                Le problème est que toutes les données nous parviennent
                à travers la méthode <span class="new_code">getValue()</span>
                et que nous voulons des résultats différents pour des clefs différentes.
                Heureusement les objets fantaisie ont un système de filtrage...
<pre>
<strong>$config = &amp;new MockConfiguration($this);
$config-&gt;setReturnValue('getValue', 'primary', array('db_host'));
$config-&gt;setReturnValue('getValue', 'admin', array('db_user'));
$config-&gt;setReturnValue('getValue', 'secret', array('db_password'));</strong>
</pre>
                Le paramètre en plus est une liste d'arguments
                à faire correspondre. Dans ce cas nous essayons
                de faire correspondre un unique argument :
                en l'occurrence la clef recherchée.
                Maintenant que la méthode <span class="new_code">getValue()</span>
                est invoquée sur l'objet fantaisie...
<pre>
$config-&gt;getValue('db_user')
</pre>
                ...elle renverra "admin".
                Elle le trouve en essayant de faire correspondre
                les arguments entrants dans sa liste
                d'arguments sortants les uns après les autres
                jusqu'au moment où une correspondance exacte est atteinte.
            </p>
            <p>
                Il y a des fois où vous souhaitez
                qu'un objet spécifique soit servi par la fantaisie
                plutôt qu'une copie.
                De nouveau c'est identique au mécanisme des bouchons serveur...
<pre>
class Thing {
}

class Vector {
    function Vector() {
    }
    
    function get($index) {
    }
}
</pre>
                Dans ce cas vous pouvez placer une référence
                dans la liste renvoyée par l'objet fantaisie...
<pre>
$thing = new Thing();<strong>
$vector = &amp;new MockVector($this);
$vector-&gt;setReturnReference('get', $thing, array(12));</strong>
</pre>
                Avec cet arrangement vous savez qu'à chaque appel
                de <span class="new_code">$vector-&gt;get(12)</span>
                le même <span class="new_code">$thing</span> sera renvoyé.
            </p>
        
        <p><a class="target" name="attentes"><h2>Objets fantaisie en critique</h2></a></p>
            <p>
                Même si les bouchons serveur vous isolent
                du désordre du monde réel, il ne s'agit là que
                de la moitié du bénéfice potentiel.
                Vous pouvez avoir une classe de test recevant
                les messages ad hoc, mais est-ce que votre nouvelle classe
                renvoie bien les bons ?
                Le tester peut devenir cafouillis sans une librairie d'objets fantaisie.
            </p>
            <p>
                Pour l'exemple, prenons une classe <span class="new_code">SessionPool</span>
                à laquelle nous allons ajouter une fonction de log.
                Plutôt que de complexifier la classe originale,
                nous souhaitons ajouter ce comportement avec un décorateur (GOF).
                Pour l'instant le code de <span class="new_code">SessionPool</span> ressemble à...
<pre>
<strong>class SessionPool {
    function SessionPool() {
        ...
    }
    
    function &amp;findSession($cookie) {
        ...
    }
    ...
}

class Session {
    ...
}</strong>

</pre>
                Alors que pour notre code de log, nous avons...
<pre><strong>
class Log {
    function Log() {
        ...
    }
    
    function message() {
        ...
    }
}

class LoggingSessionPool {
    function LoggingSessionPool(&amp;$session_pool, &amp;$log) {
        ...
    }
    
    function &amp;findSession($cookie) {
        ...
    }
    ...
}</strong>
</pre>
                Dans tout ceci, la seule classe à tester est
                <span class="new_code">LoggingSessionPool</span>. En particulier,
                nous voulons vérifier que la méthode <span class="new_code">findSession()</span>
                est appelée avec le bon identifiant de session au sein du cookie
                et qu'elle renvoie bien le message "Starting session $cookie"
                au loggueur.
            </p>
            <p>
                Bien que nous ne testions que quelques lignes
                de code de production, voici la liste des choses
                à faire dans un scénario de test conventionnel :
                <ol>
                    <li>Créer un objet de log.</li>
                    <li>Indiquer le répertoire d'écriture du fichier de log.</li>
                    <li>Modifier les droits sur le répertoire pour pouvoir y écrire le fichier.</li>
                    <li>Créer un objet <span class="new_code">SessionPool</span>.</li>
                    <li>Lancer une session, ce qui demande probablement pas mal de choses.</li>
                    <li>Invoquer <span class="new_code">findSession()</span>.</li>
                    <li>Lire le nouvel identifiant de session (en espérant qu'il existe un accesseur !).</li>
                    <li>Lever une assertion de test pour vérifier que cet identifiant correspond bien au cookie.</li>
                    <li>Lire la dernière ligne du fichier de log.</li>
                    <li>Supprimer avec une (ou plusieurs) expression rationnelle les timestamps de log en trop, etc.</li>
                    <li>Vérifier que le message de session est bien dans le texte.</li>
                </ol>
                Pas étonnant que les développeurs détestent
                écrire des tests quand ils sont aussi ingrats.
                Pour rendre les choses encore pire, à chaque fois que
                le format de log change ou bien que la méthode de création
                des sessions change, nous devons réécrire une partie
                des tests alors même qu'ils ne testent pas ces parties
                du système. Nous sommes en train de préparer
                le cauchemar pour les développeurs de ces autres classes.
            </p>
            <p>
                A la place, voici la méthode complète pour le test
                avec un peu de magie via les objets fantaisie...
<pre>
Mock::generate('Session');
Mock::generate('SessionPool');
Mock::generate('Log');

class LoggingSessionPoolTest extends UnitTestCase {
    ...
    function testFindSessionLogging() {<strong>
        $session = &amp;new MockSession($this);
        $pool = &amp;new MockSessionPool($this);
        $pool-&gt;setReturnReference('findSession', $session);
        $pool-&gt;expectOnce('findSession', array('abc'));
        
        $log = &amp;new MockLog($this);
        $log-&gt;expectOnce('message', array('Starting session abc'));
        
        $logging_pool = &amp;new LoggingSessionPool($pool, $log);
        $this-&gt;assertReference($logging_pool-&gt;findSession('abc'), $session);
        $pool-&gt;tally();
        $log-&gt;tally();</strong>
    }
}
</pre>
                Commençons par écrire une session simulacre.
                Pas la peine d'être trop pointilleux avec
                celle-ci puisque la vérification de la session
                désirée est effectuée ailleurs. Nous avons
                juste besoin de vérifier qu'il s'agit de
                la même que celle qui vient du groupe commun des sessions.
            </p>
            <p>
                <span class="new_code">findSession()</span> est un méthode fabrique
                dont la simulation est décrite <a href="#stub">plus haut</a>.
                Le point de départ vient avec le premier appel
                <span class="new_code">expectOnce()</span>. Cette ligne indique
                qu'à chaque fois que <span class="new_code">findSession()</span>
                est invoqué sur l'objet fantaisie, il vérifiera
                les arguments entrant. S'il ne reçoit
                que la chaîne "abc" en tant qu'argument
                alors un succès est envoyé au testeur unitaire,
                sinon c'est un échec qui est généré.
                Il s'agit là de la partie qui teste si nous avons bien
                la bonne session. La liste des arguments suit
                une format identique à celui qui précise les valeurs renvoyées.
                Vous pouvez avoir des jokers et des séquences
                et l'ordre de l'évaluation restera le même.
            </p>
            <p>
                Si l'appel n'est jamais effectué alors n'est généré
                ni le succès, ni l'échec. Pour contourner cette limitation,
                nous devons dire à l'objet fantaisie que le test est terminé :
                il pourra alors décider si les attentes ont été répondues.
                L'assertion du testeur unitaire de ceci est déclenchée
                par l'appel <span class="new_code">tally()</span> à la fin du test.
            </p>
            <p>
                Nous utilisons le même modèle pour mettre sur pied
                le loggueur fantaisie. Nous lui indiquons que <span class="new_code">message()</span>
                devrait être invoqué une fois et une fois seulement
                avec l'argument "Starting session abc".
                En testant les arguments d'appel, plutôt que ceux de sortie du loggueur,
                nous isolons le test de tout modification dans le loggueur.
            </p>
            <p>
                Nous commençons le lancement nos tests à la création
                du nouveau <span class="new_code">LoggingSessionPool</span>
                et nous l'alimentons avec nos objets fantaisie juste créés.
                Désormais tout est sous contrôle. Au final nous confirmons
                que le <span class="new_code">$session</span> donné au décorateur est bien
                celui reçu et prions les objets fantaisie de lancer leurs
                tests de comptage d'appel interne avec les appels <span class="new_code">tally()</span>.
            </p>
            <p>
                Il y a encore pas mal de code de test, mais ce code est très strict.
                S'il vous semble encore terrifiant il l'est bien moins
                que si nous avions essayé sans les objets fantaisie
                et ce test en particulier, interactions plutôt que résultat,
                est toujours plus difficile à mettre en place.
                Le plus souvent vous aurez besoin de tester des situations
                plus complexes sans ce niveau ni cette précision.
                En outre une partie peut être remaniée avec la méthode
                de scénario de test <span class="new_code">setUp()</span>.
            </p>
            <p>
                Voici la liste complète des attentes que vous pouvez
                placer sur un objet fantaisie avec
                <a href="http://www.lastcraft.com/simple_test.php">SimpleTest</a>...
                <table>
<thead>
                    <tr>
<th>Attente</th>
<th>Nécessite <span class="new_code">tally()</span>
</th>
</tr>
                    </thead>
<tbody>
<tr>
                        <td><span class="new_code">expectArguments($method, $args)</span></td>
                        <td style="text-align: center">Non</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectArgumentsAt($timing, $method, $args)</span></td>
                        <td style="text-align: center">Non</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectCallCount($method, $count)</span></td>
                        <td style="text-align: center">Oui</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectMaximumCallCount($method, $count)</span></td>
                        <td style="text-align: center">Non</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectMinimumCallCount($method, $count)</span></td>
                        <td style="text-align: center">Oui</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectNever($method)</span></td>
                        <td style="text-align: center">Non</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectOnce($method, $args)</span></td>
                        <td style="text-align: center">Oui</td>
                    </tr>
                    <tr>
                        <td><span class="new_code">expectAtLeastOnce($method, $args)</span></td>
                        <td style="text-align: center">Oui</td>
                    </tr>
                </tbody>
</table>
                Où les paramètres sont...
                <dl>
                    <dt class="new_code">$method</dt>
                    <dd>Le nom de la méthode, sous la forme d'une chaîne,
                    à laquelle la condition doit être appliquée.</dd>
                    <dt class="new_code">$args</dt>
                    <dd>
                        Les arguments sous la forme d'une liste.
                        Les jokers peuvent être inclus de la même manière
                        qu'avec <span class="new_code">setReturn()</span>.
                        Cet argument est optionnel pour <span class="new_code">expectOnce()</span>
                        et <span class="new_code">expectAtLeastOnce()</span>.
                    </dd>
                    <dt class="new_code">$timing</dt>
                    <dd>
                        Le seul point dans le temps pour tester
                        la condition. Le premier appel commence à zéro.
                    </dd>
                    <dt class="new_code">$count</dt>
                    <dd>Le nombre d'appels attendu.</dd>
                </dl>
                La méthode <span class="new_code">expectMaximumCallCount()</span>
                est légèrement différente dans le sens où elle ne pourra
                générer qu'un échec. Elle reste silencieuse
                si la limite n'est jamais atteinte.
            </p>
            <p>
                Par ailleurs si vous avez just un appel dans votre test,
                vérifiez bien que vous utiliser
                <span class="new_code">expectOnce</span>.<br>
                Utiliser <span class="new_code">$mocked-&gt;expectAt(0, 'method', 'args);</span>
                tout seul ne sera pas pris en compte :
                la vérification des arguments et le comptage total
                sont pour l'instant encore indépendant.
            </p>
            <p>
                Comme avec les assertions dans les scénarios de test,
                toutes ces attentes peuvent accepter une surcharge de
                message sous la forme d'un paramètre supplémentaire.
                Par ailleurs le message d'échec original peut être inclus
                dans le résultat avec "%s".
            </p>
        
        <p><a class="target" name="approches"><h2>D'autres approches</h2></a></p>
            <p>
                Il existe trois approches pour créer des objets
                fantaisie en comprenant celle utilisée par SimpleTest.
                Les coder à la main en utilisant une classe de base,
                les générer dans un fichier ou les générer dynamiquement à la volée.
            </p>
            <p>
                Les objets fantaisie générés avec
                <a href="simple_test.html">SimpleTest</a> sont dynamiques.
                Ils sont créés à l'exécution dans la mémoire,
                grâce à <span class="new_code">eval()</span>, plutôt qu'écrits dans un fichier.
                Cette opération les rend facile à créer,
                en une seule ligne, surtout par rapport à leur création
                à la main dans une hiérarchie de classe parallèle.
                Le problème avec ce comportement tient généralement
                dans la mise en place des tests proprement dits.
                Si les objets originaux changent les versions fantaisie
                sur lesquels reposent les tests, une désynchronisation peut subvenir.
                Cela peut aussi arriver avec l'approche en hiérarchie parallèle,
                mais c'est détecté beaucoup plus vite.
            </p>
            <p>
                Bien sûr, la solution est d'ajouter de véritables tests d'intégration.
                Vous n'en avez pas besoin de beaucoup
                et le côté pratique des objets fantaisie fait plus
                que compenser la petite dose de test supplémentaire.
                Vous ne pouvez pas avoir confiance dans du code qui
                ne serait testé que par des objets fantaisie.
            </p>
            <p>
                Si vous restez déterminé de construire des librairies
                statiques d'objets fantaisie parce que vous souhaitez
                émuler un comportement très spécifique,
                vous pouvez y parvenir grâce au générateur de classe de SimpleTest.
                Dans votre fichier librairie, par exemple
                <em>mocks/connection.php</em> pour une connexion à une base de données,
                créer un objet fantaisie et provoquer l'héritage
                pour hériter pour surcharger des méthodes spéciales
                ou ajouter des préréglages...
<pre>
&lt;?php
    require_once('simpletest/mock_objects.php');
    require_once('../classes/connection.php');
<strong>
    Mock::generate('Connection', 'BasicMockConnection');
    class MockConnection extends BasicMockConnection {
        function MockConnection(&amp;$test, $wildcard = '*') {
            $this-&gt;BasicMockConnection($test, $wildcard);
            $this-&gt;setReturn('query', false);
        }
    }</strong>
?&gt;
</pre>
                L'appel <span class="new_code">generate</span> dit au générateur de classe
                d'en créer une appelée <span class="new_code">BasicMockConnection</span>
                plutôt que la plus courante <span class="new_code">MockConnection</span>.
                Ensuite nous héritons à partir de celle-ci pour obtenir
                notre version de <span class="new_code">MockConnection</span>.
                En interceptant de cette manière nous pouvons ajouter
                un comportement, ici transformer la valeur par défaut de
                <span class="new_code">query()</span> en "false".
                En utilisant le nom par défaut nous garantissons
                que le générateur de classe fantaisie n'en recréera
                pas une autre différente si il est invoqué ailleurs
                dans les tests. Il ne créera jamais de classe
                si elle existe déjà. Aussi longtemps que le fichier
                ci-dessus est inclus avant alors tous les tests qui
                généraient <span class="new_code">MockConnection</span> devraient
                utiliser notre version à présent. Par contre si
                nous avons une erreur dans l'ordre et que la librairie
                de fantaisie en crée une d'abord alors la création
                de la classe échouera tout simplement.
            </p>
            <p>
                Utiliser cette astuce si vous vous trouvez avec beaucoup
                de comportement en commun sur les objets fantaisie
                ou si vous avez de fréquents problèmes d'intégration
                plus tard dans les étapes de test.
            </p>
        
        <p><a class="target" name="autres_testeurs"><h2>Je pense que SimpleTest pue !</h2></a></p>
            <p>
                Mais au moment d'écrire ces lignes c'est le seul
                à gérer les objets fantaisie, donc vous êtes bloqué avec lui ?
            </p>
            <p>
                Non, pas du tout.
                <a href="simple_test.html">SimpleTest</a> est une boîte à outils
                et parmi ceux-ci on trouve les objets fantaisie
                qui peuvent être utilisés indépendamment.
                Supposons que vous avez votre propre testeur unitaire favori
                et que tous vos tests actuels l'utilisent.
                Prétendez que vous avez appelé votre tester unitaire PHPUnit
                (c'est ce que tout le monde a fait) et que la classe principale
                de test ressemble à...
<pre>
class PHPUnit {
    function PHPUnit() {
    }
    
    function assertion($message, $assertion) {
    }
    ...
}
</pre>
                La seule chose que la méthode <span class="new_code">assertion()</span> réalise,
                c'est de préparer une sortie embellie alors le paramètre boolien
                de l'assertion sert à déterminer s'il s'agit d'une erreur ou d'un succès.
                Supposons qu'elle est utilisée de la manière suivante...
<pre>
$unit_test = new PHPUnit();
$unit_test&gt;assertion('I hope this file exists', file_exists('my_file'));
</pre>
                Comment utiliser les objets fantaisie avec ceci ?
            </p>
            <p>
                Il y a une méthode protégée sur la classe de base
                des objets fantaisie : elle s'appelle <span class="new_code">_assertTrue()</span>.
                En surchargeant cette méthode nous pouvons utiliser
                notre propre format d'assertion.
                Nous commençons avec une sous-classe, dans <em>my_mock.php</em>...
<pre>
<strong>&lt;?php
    require_once('simpletest/mock_objects.php');
    
    class MyMock extends SimpleMock() {
        function MyMock(&amp;$test, $wildcard) {
            $this-&gt;SimpleMock($test, $wildcard);
        }
        
        function _assertTrue($assertion, $message) {
            $test = &amp;$this-&gt;getTest();
            $test-&gt;assertion($message, $assertion);
        }
    }
?&gt;</strong>
</pre>
                Maintenant une instance de <span class="new_code">MyMock</span>
                créera un objet qui parle le même langage que votre testeur.
                Bien sûr le truc c'est que nous créons jamais un tel objet :
                le générateur s'en chargera. Nous avons juste besoin
                d'une ligne de code supplémentaire pour dire au générateur
                d'utiliser vos nouveaux objets fantaisie...
<pre>
&lt;?php
    require_once('simpletst/mock_objects.php');
    
    class MyMock extends SimpleMock() {
        function MyMock($test, $wildcard) {
            $this-&gt;SimpleMock(&amp;$test, $wildcard);
        }
        
        function _assertTrue($assertion, $message , &amp;$test) {
            $test-&gt;assertion($message, $assertion);
        }
    }<strong>
    SimpleTestOptions::setMockBaseClass('MyMock');</strong>
?&gt;
</pre>
                A partir de maintenant vous avez juste à inclure
                <em>my_mock.php</em> à la place de la version par défaut
                <em>simple_mock.php</em> et vous pouvez introduire
                des objets fantaisie dans votre suite de tests existants.
            </p>
        
    </div>
        References and related information...
        <ul>
<li>
            L'article originel sur
            <a href="http://www.mockobjects.com/">les objets fantaisie</a>.
        </li>
<li>
            La page du projet SimpleTest sur
            <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
        </li>
<li>
            La page d'accueil de SimpleTest sur
            <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
        </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>