File: server_stubs_documentation.xml

package info (click to toggle)
postfixadmin 2.3.5-2%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 6,200 kB
  • sloc: php: 25,767; xml: 14,485; perl: 964; sh: 664; python: 169; makefile: 84
file content (251 lines) | stat: -rw-r--r-- 13,893 bytes parent folder | download | duplicates (2)
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
<?xml version="1.0" encoding="ISO-8859-1" ?>
<page title="Documentation sur les bouchons serveur" here="Les bouchons serveur">
    <long_title>Documentation SimpleTest : les bouchons serveur</long_title>
    <content>
        <section name="quoi" title="Que sont les bouchons serveur ?">
            <p>
                Au dpart il s'agit d'un modle de conception initi par Robert Binder (Testing object-oriented systems: models, patterns, and tools, Addison-Wesley) in 1999. Un bouchon serveur est une simulation d'un objet ou d'un composant. Il doit remplacer exactement un composant dans un systme pour des raisons de testabilit ou de prototypage, tout en restant lger. Il permet aux tests de tourner plus rapidement ou alors, si la classe simule n'a pas t crite, juste de fonctionner.
            </p>
        </section>
        <section name="creation" title="Crer des bouchons serveur">
            <p>
                Nous avons juste besoin d'une classe prexistante, par exemple une connexion vers une base de donnes qui ressemblerait ...
<php><![CDATA[
<strong>class DatabaseConnection {
    function DatabaseConnection() {
    }
    
    function query() {
    }
    
    function selectQuery() {
    }
}</strong>
]]></php>
                La classe n'a mme pas encore besoin d'avoir t implmente. Pour crer la version bouchonne de cette classe, nous incluons la librairie de bouchon serveur et excutons le gnrateur...
<php><![CDATA[
<strong>require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
Stub::generate('DatabaseConnection');</strong>
]]></php>
                Est gnr un clone de la classe appel <code>StubDatabaseConnection</code>. Nous pouvons alors crer des instances de cette nouvelle classe  l'intrieur de notre prototype de script...
<php><![CDATA[
require_once('simpletest/mock_objects.php');
require_once('database_connection.php');
Stub::generate('DatabaseConnection');
<strong>
$connection = new StubDatabaseConnection();
</strong>
]]></php>
                La version bouchonne de la classe contient toutes les mthodes de l'original de telle sorte qu'une opration comme <code><![CDATA[$connection->query()]]></code> soit encore lgale. La valeur retourne sera <code>null</code>, Mais nous pouvons y remdier avec...
<php><![CDATA[
<strong>$connection->setReturnValue('query', 37)</strong>
]]></php>
                Dsormais  chaque appel de <code><![CDATA[$connection->query()]]></code> nous obtenons un rsultat de 37. Nous pouvons choisir n'importe quelle valeur pour le rsultat, par exemple un hash de rsultats provenant d'une base de donnes imaginaire ou alors une liste d'objets persistants. Peu importe les paramtres, nous obtenons systmatiquement les mme valeurs chaque fois qu'ils ont t initialiss de la sorte : a ne ressemble peut-tre pas  une rponse convaincante venant d'une connexion vers une base de donnes. Mais pour la demi-douzaine de lignes d'une mthode de test c'est souvent largement suffisant.
            </p>
        </section>
        <section name="modles" title="Modles de simulation">
            <p>
                Sauf que les choses ne sont que rarement aussi simples. Parmi les problmes les plus courants on trouve les itrateurs : le renvoi d'une valeur constante peut causer une boucle infini dans l'objet test. Pour ceux-ci nous avons besoin de mettre sur pied une suite de valeurs. Prenons par exemple un itrateur simple qui ressemble ...
<php><![CDATA[
class Iterator {
    function Iterator() {
    }
    
    function next() {
    }
}
]]></php>
                C'est probablement le plus simple des itrateurs possibles. Supposons que cet itrateur ne retourne que du texte, jusqu' la fin - quand il retourne <code>false</code>. Une simulation est possible avec...
<php><![CDATA[
<strong>Stub::generate('Iterator');

$iterator = new StubIterator();
$iterator->setReturnValue('next', false);
$iterator->setReturnValueAt(0, 'next', 'First string');
$iterator->setReturnValueAt(1, 'next', 'Second string');</strong>
]]></php>
                A l'appel de <code>next()</code> sur l'itrateur bouchonn il va d'abord renvoyer &quot;First string&quot;, puis au second appel c'est &quot;Second string&quot; qui sera renvoy. Finalement pour tous les autres appels, il s'agira d'un <code>false</code>. Les valeurs renvoyes successivement ont priorit sur la valeur constante renvoy. Cette dernire est un genre de valeur par dfaut.
            </p>
            <p>
                Une autre situation dlicate est une opration <code>get()</code> surcharge. Un exemple ? Un porteur d'information avec des pairs de clef / valeur. Prenons une classe de configuration...
<php><![CDATA[
class Configuration {
    function Configuration() {
    }
    
    function getValue($key) {
    }
}
]]></php>
                Il s'agit d'une situation propice  l'utilisation d'objets bouchon, surtout que la configuration en production dpend invariablement de la machine : l'utiliser directement ne va pas nous aider  maintenir notre confiance dans nos tests. Sauf que le problme tient de ce que toutes les donnes proviennent de la mthode <code>getValue()</code> et que nous voulons des rsultats diffrents suivant la clef. Par chance les bouchons ont un systme de filtre...
<php><![CDATA[
<strong>Stub::generate('Configuration');

$config = &new StubConfiguration();
$config->setReturnValue('getValue', 'primary', array('db_host'));
$config->setReturnValue('getValue', 'admin', array('db_user'));
$config->setReturnValue('getValue', 'secret', array('db_password'));</strong>
]]></php>
                Ce paramtre supplmentaire est une liste d'arguments que l'on peut utiliser. Dans ce cas nous essayons d'utiliser un unique argument,  savoir la clef recherche. Maintenant quand on invoque le bouchon serveur via la mthode <code>getValue()</code> avec...
<php><![CDATA[
$config->getValue('db_user');
]]></php>
                ...il renvoie &quot;admin&quot;. Il le trouve en essayant d'assortir successivement les arguments d'entre avec sa liste de ceux de sortie jusqu'au moment o une correspondance exacte est trouve.
            </p>
            <p>
                Vous pouvez dfinir un argument par dfaut avec...
<php><![CDATA[<strong>
$config->setReturnValue('getValue', false, array('*'));</strong>
]]></php>
                Attention ce n'est pas quivalent  initialiser la valeur retourne sans aucun argument.
<php><![CDATA[<strong>
$config->setReturnValue('getValue', false);</strong>
]]></php>
                Dans le premier cas il acceptera n'importe quel argument, mais exactement un -- pas plus -- est ncessaire. Dans le second cas n'importe quel nombre d'arguments fera l'affaire : il agit comme un <cite>catchall</cite> aprs tous les correspondances. Prenez garde  l'ordre : si nous ajoutons un autre paramtre aprs le joker ('*') il sera ignor puisque le joker aura t trouv auparavant. Avec des listes de paramtres complexes l'ordre peut devenir crucial, au risque de perdre des correspondances souhaites, masques par un joker antrieur. Pensez  mettre d'abord les cas les plus spcifiques si vous n'tes pas sr.
            </p>
            <p>
                Il y a des fois o l'on souhaite qu'un objet spcifique soit servi par le bouchon plutt qu'une simple copie. La smantique de la copie en PHP nous force  utiliser une autre mthode pour cela. Vous tes peut-tre en train de simuler un conteneur par exemple...
<php><![CDATA[
class Thing {
}

class Vector {
    function Vector() {
    }
    
    function get($index) {
    }
}
]]></php>
                Dans ce cas vous pouvez mettre une rfrence dans la liste renvoye par le bouchon...
<php><![CDATA[
Stub::generate('Vector');

$thing = new Thing();<strong>
$vector = &new StubVector();
$vector->setReturnReference('get', $thing, array(12));</strong>
]]></php>
                Avec ce petit arrangement vous vous assurez qu' chaque fois que <code><![CDATA[$vector->get(12)]]></code> est appel il renverra le mme <code>$thing</code>.
            </p>
            <p>
                Ces trois facteurs, ordre, paramtres et copie (ou rfrence), peuvent tre combins orthogonalement. Par exemple...
<php><![CDATA[
$complex = &new StubComplexThing();
$stuff = new Stuff();<strong>
$complex->setReturnReferenceAt(3, 'get', $stuff, array('*', 1));</strong>
]]></php>
                Le <code>$stuff</code> ne sera renvoy qu'au troisime appel et seulement si deux paramtres taient indiqus, avec la contrainte que le second de ceux-ci soit l'entier 1. N'est-ce pas suffisant pour des situations de prototypage simple ?
            </p>
            <p>
                Un dernier cas critique reste celle d'un objet en crant un autre, connu sous le nom du modle factory - fabrique. Supposons qu'aprs une requte russie  notre base de donnes imaginaire, un ensemble de rsultats est retourn sous la forme d'un itrateur, chaque appel  <code>next()</code> donnant une ligne et  la fin un <code>false</code>.
                Au premier abord, a donne l'impression d'tre cauchemardesque  simuler. Alors qu'en fait tout peut tre bouchonn en utilisant les mcanismes ci-dessus.
            </p>
            <p>
                Voici comment...
<php><![CDATA[
Stub::generate('DatabaseConnection');
Stub::generate('ResultIterator');

class DatabaseTest extends UnitTestCase {
    
    function testUserFinder() {<strong>
        $result = &new StubResultIterator();
        $result->setReturnValue('next', false);
        $result->setReturnValueAt(0, 'next', array(1, 'tom'));
        $result->setReturnValueAt(1, 'next', array(3, 'dick'));
        $result->setReturnValueAt(2, 'next', array(6, 'harry'));
        
        $connection = &new StubDatabaseConnection();
        $connection->setReturnValue('query', false);
        $connection->setReturnReference(
                'query',
                $result,
                array('select id, name from users'));</strong>
                
        $finder = &new UserFinder($connection);
        $this->assertIdentical(
                $finder->findNames(),
                array('tom', 'dick', 'harry'));
    }
}
]]></php>
                Dsormais ce n'est que si notre <code>$connection</code> est appel avec la bonne <code>query()</code> que le <code>$result</code> sera renvoy aprs le troisime appel  <code>next()</code>. Cela devrait tre suffisant pour que notre classe <code>UserFinder</code>, la classe effectivement teste  ce niveau, puisse s'excuter comme il faut. Un test trs prcis et pas une seule base de donnes  l'horizon.
            </p>
        </section>
        <section name="options" title="Options de cration pour les bouchons">
            <p>
                Il y a d'autres options additionnelles  la cration d'un bouchon. Au moment de la gnration nous pouvons changer le nom de la classe...
<php><![CDATA[
<strong>Stub::generate('Iterator', 'MyStubIterator');
$iterator = &new MyStubIterator();
</strong>
]]></php>
                Pris tout seul ce n'est pas trs utile tant donn qu'il n'y aurait pas de diffrence entre cette classe et celle par dfaut --  part le nom bien entendu. Par contre nous pouvons aussi lui ajouter d'autres mthodes qui ne se trouveraient pas dans l'interface originale...
<php><![CDATA[
class Iterator {
}
<strong>Stub::generate('Iterator', 'PrototypeIterator', array('next', 'isError'));
$iterator = &new PrototypeIterator();
$iterator->setReturnValue('next', 0);
</strong>
]]></php>
                Les mthodes <code>next()</code> et <code>isError()</code> peuvent maintenant renvoyer des ensembles de valeurs exactement comme si elles existaient dans la classe originale.
            </p>
            <p>
                Un moyen encore plus sotrique de modifier les bouchons est de changer le joker utilis par dfaut pour la correspondance des paramtres.
<php><![CDATA[
<strong>Stub::generate('Connection');
$iterator = &new StubConnection('wild');
$iterator->setReturnValue('query', array('id' => 33), array('wild'));
</strong>
]]></php>
                L'unique raison valable pour effectuer cette opration, c'est quand vous souhaitez tester la chane &quot;*&quot; sans pour autant l'interprter comme un &quot;n'importe lequel&quot;.
            </p>
        </section>
    </content>
    <internal>
        <link>
            <a href="#quoi">Que sont les bouchons ?</a>
        </link>
        <link>
            <a href="#creation">Crer des bouchons serveur</a> avec SimpleTest.
        </link>
        <link>
            <a href="#modeles">Modles de simulation</a> pour simuler des interactions d'objet plus complexes.
        </link>
        <link>
            <a href="#options">Options  la gnration</a> pour diffrents contextes.
        </link>
    </internal>
    <external>
        <link>
            La page du projet SimpleTest sur <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
        </link>
        <link>
            La page de tlchargement de SimpleTest sur <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
        </link>
        <link>
            <a href="http://simpletest.sourceforge.net/">L'API complte pour SimpleTest</a> gnre par PHPDoc.
        </link>
    </external>
    <meta>
        <keywords>
            dveloppement logiciel,
            programmation php,
            outils de dveloppement logiciel,
            tutoriel php,
            outil gratuit de test pour php,
            architecture,
            ressuorces php,
            objets fantaisie,
            prototypage avec langage de scripts,
            bouchons serveur,
            test unitaire,
            prototypage en php,
            mthodes de test,
            mthodologie de test
        </keywords>
    </meta>
</page>