File: expectation_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 (213 lines) | stat: -rw-r--r-- 12,748 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
<?xml version="1.0" encoding="ISO-8859-1" ?>
<page title="Documentation sur les attentes" here="Les attentes">
    <long_title>Documentation SimpleTest : tendre le testeur unitaire avec des classes d'attentes supplmentaires</long_title>
    <content>
        <section name="fantaisie" title="Plus de contrle sur les objets fantaisie">
            <p>
                Le comportement par dfaut des <a local="mock_objects_documentation">objets fantaisie</a> dans <a href="http://sourceforge.net/projects/simpletest/">SimpleTest</a> est soit une correspondance identique sur l'argument, soit l'acceptation de n'importe quel argument. Pour la plupart des tests, c'est suffisant. Cependant il est parfois ncessaire de ramollir un scnario de test.
            </p>
            <p>
                Un des endroits o un test peut tre trop serr est la reconnaissance textuelle. Prenons l'exemple d'un composant qui produirait un message d'erreur utile lorsque quelque chose plante. Il serait utile de tester que l'erreur correcte est renvoye, mais le texte proprement dit risque d'tre plutt long. Si vous testez le texte dans son ensemble alors  chaque modification de ce mme message -- mme un point ou une virgule -- vous aurez  revenir sur la suite de test pour la modifier.
            </p>
            <p>
                Voici un cas concret, nous avons un service d'actualits qui a chou dans sa tentative de connexion  sa source distante.
<php><![CDATA[
<strong>class NewsService {
    ...
    function publish(&$writer) {
        if (! $this->isConnected()) {
            $writer->write('Cannot connect to news service "' .
                    $this->_name . '" at this time. ' .
                    'Please try again later.');
        }
        ...
    }
}</strong>
]]></php>
                L il envoie son contenu vers un classe <code>Writer</code>. Nous pourrions tester ce comportement avec un <code>MockWriter</code>...
<php><![CDATA[
class TestOfNewsService extends UnitTestCase {
    ...
    function testConnectionFailure() {<strong>
        $writer = &new MockWriter($this);
        $writer->expectOnce('write', array(
                'Cannot connect to news service ' .
                '"BBC News" at this time. ' .
                'Please try again later.'));
        
        $service = &new NewsService('BBC News');
        $service->publish($writer);
        
        $writer->tally();</strong>
    }
}
]]></php>
                C'est un bon exemple d'un test fragile. Si nous dcidons d'ajouter des instructions complmentaires, par exemple proposer une source d'actualits alternative, nous casserons nos tests par la mme occasion sans pourtant avoir modifi une seule fonctionnalit.
            </p>
            <p>
                Pour contourner ce problme, nous voudrions utiliser un test avec une expression rationnelle plutt qu'une correspondance exacte. Nous pouvons y parvenir avec...
<php><![CDATA[
class TestOfNewsService extends UnitTestCase {
    ...
    function testConnectionFailure() {
        $writer = &new MockWriter($this);<strong>
        $writer->expectOnce(
                'write',
                array(new WantedPatternExpectation('/cannot connect/i')));</strong>
        
        $service = &new NewsService('BBC News');
        $service->publish($writer);
        
        $writer->tally();
    }
}
]]></php>
                Plutt que de transmettre le paramtre attendu au <code>MockWriter</code>, nous envoyons une classe d'attente appele <code>WantedPatternExpectation</code>. L'objet fantaisie est suffisamment lgant pour reconnatre qu'il s'agit d'un truc spcial et pour le traiter diffremment. Plutt que de comparer l'argument entrant  cet objet, il utilise l'objet attente lui-mme pour excuter le test.
            </p>
            <p>
                <code>WantedPatternExpectation</code> utilise l'expression rationnelle pour la comparaison avec son constructeur. A chaque fois qu'une comparaison est fait  travers <code>MockWriter</code> par rapport  cette classe attente, elle fera un <code>preg_match()</code> avec ce motif. Dans notre scnario de test ci-dessus, aussi longtemps que la chane &quot;cannot connect&quot; apparat dans le texte, la fantaisie transmettra un succs au testeur unitaire. Peu importe le reste du texte.
            </p>
            <p>
                Les classes attente possibles sont...
                <table><tbody>
                    <tr><td><code>EqualExpectation</code></td><td>Une galit, plutt que la plus forte comparaison  l'identique</td></tr>
                    <tr><td><code>NotEqualExpectation</code></td><td>Une comparaison sur la non-galit</td></tr>
                    <tr><td><code>IndenticalExpectation</code></td><td>La vrification par dfaut de l'objet fantaisie qui doit correspondre exactement</td></tr>
                    <tr><td><code>NotIndenticalExpectation</code></td><td>Inverse la logique de l'objet fantaisie</td></tr>
                    <tr><td><code>WantedPatternExpectation</code></td><td>Utilise une expression rationnelle Perl pour comparer une chane</td></tr>
                    <tr><td><code>NoUnwantedPatternExpectation</code></td><td>Passe seulement si l'expression rationnelle Perl choue</td></tr>
                    <tr><td><code>IsAExpectation</code></td><td>Vrifie le type ou le nom de la classe uniquement</td></tr>
                    <tr><td><code>NotAExpectation</code></td><td>L'oppos de <code>IsAExpectation</code></td></tr>
                    <tr><td><code>MethodExistsExpectation</code></td><td>Vrifie si la mthode est disponible sur un objet</td></tr>
                </tbody></table>
                La plupart utilisent la valeur attendue dans le constructeur. Les exceptions sont les vrifications sur motif, qui utilisent une expression rationnelle, ainsi que <code>IsAExpectation</code> et <code>NotAExpectation</code>, qui prennent un type ou un nom de classe comme chane.
            </p>
        </section>
        <section name="comportement" title="Utiliser les attentes pour contrler les bouchons serveur">
            <p>
                Les classes attente peuvent servir  autre chose que l'envoi d'assertions depuis les objets fantaisie, afin de choisir le comportement d'un <a local="mock_objects_documentation">objet fantaisie</a> ou celui d'un <a local="server_stubs_documentation">bouchon serveur</a>. A chaque fois qu'une liste d'arguments est donne, une liste d'objets d'attente peut tre insre  la place.
            </p>
            <p>
                Mettons que nous voulons qu'un bouchon serveur d'autorisation simule une connexion russie seulement si il reoit un objet de session valide. Nous pouvons y arriver avec ce qui suit...
<php><![CDATA[
Stub::generate('Authorisation');
<strong>
$authorisation = new StubAuthorisation();
$authorisation->setReturnValue(
        'isAllowed',
        true,
        array(new IsAExpectation('Session', 'Must be a session')));
$authorisation->setReturnValue('isAllowed', false);</strong>
]]></php>
                Le comportement par dfaut du bouchon serveur est dfini pour renvoyer <code>false</code> quand <code>isAllowed</code> est appel. Lorsque nous appelons cette mthode avec un unique paramtre qui est un objet <code>Session</code>, il renverra <code>true</code>. Nous avons aussi ajout un deuxime paramtre comme message. Il sera affich dans le message d'erreur de l'objet fantaisie si l'attente est la cause de l'chec.
            </p>
            <p>
                Ce niveau de sophistication est rarement utile : il n'est inclut que pour tre complet.
            </p>
        </section>
        <section name="etendre" title="Crer vos propres attentes">
            <p>
                Les classes d'attentes ont une structure trs simple. Tellement simple qu'il devient trs simple de crer vos propres version de logique pour des tests utiliss couramment.
            </p>
            <p>
                Par exemple voici la cration d'une classe pour tester la validit d'adresses IP. Pour fonctionner correctement avec les bouchons serveurs et les objets fantaisie, cette nouvelle classe d'attente devrait tendre <code>SimpleExpectation</code>...
<php><![CDATA[
<strong>class ValidIp extends SimpleExpectation {
    
    function test($ip) {
        return (ip2long($ip) != -1);
    }
    
    function testMessage($ip) {
        return "Address [$ip] should be a valid IP address";
    }
}</strong>
]]></php> 
               Il n'y a vritablement que deux mthodes  mettre en place. La mthode <code>test()</code> devrait renvoyer un <code>true</code> si l'attente doit passer, et une erreur <code>false</code> dans le cas contraire. La mthode <code>testMessage()</code> ne devrait renvoyer que du texte utile  la comprhension du test en lui-mme.
            </p>
            <p>
                Cette classe peut dsormais tre employe  la place des classes d'attente prcdentes.
            </p>
        </section>
        <section name="unitaire" title="Sous le capot du testeur unitaire">
            <p>
                Le <a href="http://sourceforge.net/projects/simpletest/">framework de test unitaire SimpleTest</a> utilise aussi dans son coeur des classes d'attente pour la <a local="unit_test_documentation">classe UnitTestCase</a>. Nous pouvons aussi tirer parti de ces mcanismes pour rutiliser nos propres classes attente  l'intrieur mme des suites de test.
            </p>
            <p>
                La mthode la plus directe est d'utiliser la mthode <code>SimpleTest::assertExpectation()</code> pour effectuer le test...
<php><![CDATA[
<strong>class TestOfNetworking extends UnitTestCase {
    ...
    function testGetValidIp() {
        $server = &new Server();
        $this->assertExpectation(
                new ValidIp(),
                $server->getIp(),
                'Server IP address->%s');
    }
}</strong>
]]></php>
                C'est plutt sale par rapport  notre syntaxe habituelle du type <code>assert...()</code>.
            </p>
            <p>
                Pour un cas aussi simple, nous crons d'ordinaire une mthode d'assertion distincte en utilisant la classe d'attente. Supposons un instant que notre attente soit un peu plus complique et que par consquent nous souhaitions la rutiliser, nous obtenons...
<php><![CDATA[
class TestOfNetworking extends UnitTestCase {
    ...<strong>
    function assertValidIp($ip, $message = '%s') {
        $this->assertExpectation(new ValidIp(), $ip, $message);
    }</strong>
    
    function testGetValidIp() {
        $server = &new Server();<strong>
        $this->assertValidIp(
                $server->getIp(),
                'Server IP address->%s');</strong>
    }
}
]]></php>
                Il est peu probable que nous ayons besoin de ce niveau de contrle sur la machinerie de test. Il est assez rare que le besoin d'une attente dpasse le stade de la reconnaissance d'un motif. De plus, les classes d'attente complexes peuvent rendre les tests difficiles  lire et  dboguer. Ces mcanismes sont vritablement l pour les auteurs de systme qui tendront le framework de test pour leurs propres outils de test.
            </p>
        </section>
    </content>
    <internal>
        <link>
            Utiliser les attentes <a href="#fantaisie">pour des tests plus prcis avec des objets fantaisie</a>
        </link>
        <link>
            <a href="#comportement">Changer le comportement d'un objet fantaisie</a> avec des attentes
        </link>
        <link>
            <a href="#etendre">Crer des attentes</a>
        </link>
        <link>
            Par dessous SimpleTest <a href="#unitaire">utilise des classes d'attente</a>
        </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>
            Les attentes imitent les contraintes dans <a href="http://www.jmock.org/">JMock</a>.
        </link>
        <link>
            <a href="http://simpletest.sourceforge.net/">L'API complte pour SimpleTest</a> ralis avec PHPDoc.
        </link>
    </external>
    <meta>
        <keywords>
            objets fantaisie,
            dveloppement pilot par les tests,
            hritage des attentes,
            contraintes d'objet fantaisie,
            test unitaire avanc en PHP,
            test en premier,
            architecture de framework de test
        </keywords>
    </meta>
</page>