source: trunk/server/www/vendors/simpletest/docs/en/expectation_documentation.html @ 6

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

Added SimpleTest? test framework

File size: 16.7 KB
Line 
1<html>
2<head>
3<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
4<title>
5        Extending the SimpleTest unit tester with additional expectation classes
6    </title>
7<link rel="stylesheet" type="text/css" href="docs.css" title="Styles">
8</head>
9<body>
10<div class="menu_back"><div class="menu">
11<a href="index.html">SimpleTest</a>
12                |
13                <a href="overview.html">Overview</a>
14                |
15                <a href="unit_test_documentation.html">Unit tester</a>
16                |
17                <a href="group_test_documentation.html">Group tests</a>
18                |
19                <a href="mock_objects_documentation.html">Mock objects</a>
20                |
21                <a href="partial_mocks_documentation.html">Partial mocks</a>
22                |
23                <a href="reporter_documentation.html">Reporting</a>
24                |
25                <span class="chosen">Expectations</span>
26                |
27                <a href="web_tester_documentation.html">Web tester</a>
28                |
29                <a href="form_testing_documentation.html">Testing forms</a>
30                |
31                <a href="authentication_documentation.html">Authentication</a>
32                |
33                <a href="browser_documentation.html">Scriptable browser</a>
34</div></div>
35<h1>Expectation documentation</h1>
36        This page...
37        <ul>
38<li>
39            Using expectations for
40            <a href="#mock">more precise testing with mock objects</a>
41        </li>
42<li>
43            <a href="#behaviour">Changing mock object behaviour</a> with expectations
44        </li>
45<li>
46            <a href="#extending">Extending the expectations</a>
47        </li>
48<li>
49            Underneath SimpleTest <a href="#unit">uses expectation classes</a>
50        </li>
51</ul>
52<div class="content">
53        <p><a class="target" name="mock"><h2>More control over mock objects</h2></a></p>
54            <p>
55                The default behaviour of the
56                <a href="mock_objects_documentation.html">mock objects</a>
57                in
58                <a href="http://sourceforge.net/projects/simpletest/">SimpleTest</a>
59                is either an identical match on the argument or to allow any argument at all.
60                For almost all tests this is sufficient.
61                Sometimes, though, you want to weaken a test case.
62            </p>
63            <p>
64                One place where a test can be too tightly coupled is with
65                text matching.
66                Suppose we have a component that outputs a helpful error
67                message when something goes wrong.
68                You want to test that the correct error was sent, but the actual
69                text may be rather long.
70                If you test for the text exactly, then every time the exact wording
71                of the message changes, you will have to go back and edit the test suite.
72            </p>
73            <p>
74                For example, suppose we have a news service that has failed
75                to connect to its remote source.
76<pre>
77<strong>class NewsService {
78    ...
79    function publish(&amp;$writer) {
80        if (! $this-&gt;isConnected()) {
81            $writer-&gt;write('Cannot connect to news service "' .
82                    $this-&gt;_name . '" at this time. ' .
83                    'Please try again later.');
84        }
85        ...
86    }
87}</strong>
88</pre>
89                Here it is sending its content to a
90                <span class="new_code">Writer</span> class.
91                We could test this behaviour with a
92                <span class="new_code">MockWriter</span> like so...
93<pre>
94class TestOfNewsService extends UnitTestCase {
95    ...
96    function testConnectionFailure() {<strong>
97        $writer = &amp;new MockWriter();
98        $writer-&gt;expectOnce('write', array(
99                'Cannot connect to news service ' .
100                '"BBC News" at this time. ' .
101                'Please try again later.'));
102       
103        $service = &amp;new NewsService('BBC News');
104        $service-&gt;publish($writer);</strong>
105    }
106}
107</pre>
108                This is a good example of a brittle test.
109                If we decide to add additional instructions, such as
110                suggesting an alternative news source, we will break
111                our tests even though no underlying functionality
112                has been altered.
113            </p>
114            <p>
115                To get around this, we would like to do a regular expression
116                test rather than an exact match.
117                We can actually do this with...
118<pre>
119class TestOfNewsService extends UnitTestCase {
120    ...
121    function testConnectionFailure() {
122        $writer = &amp;new MockWriter();<strong>
123        $writer-&gt;expectOnce(
124                'write',
125                array(new PatternExpectation('/cannot connect/i')));</strong>
126       
127        $service = &amp;new NewsService('BBC News');
128        $service-&gt;publish($writer);
129    }
130}
131</pre>
132                Instead of passing in the expected parameter to the
133                <span class="new_code">MockWriter</span> we pass an
134                expectation class called
135                <span class="new_code">WantedPatternExpectation</span>.
136                The mock object is smart enough to recognise this as special
137                and to treat it differently.
138                Rather than simply comparing the incoming argument to this
139                object, it uses the expectation object itself to
140                perform the test.
141            </p>
142            <p>
143                The <span class="new_code">WantedPatternExpectation</span> takes
144                the regular expression to match in its constructor.
145                Whenever a comparison is made by the <span class="new_code">MockWriter</span>
146                against this expectation class, it will do a
147                <span class="new_code">preg_match()</span> with this pattern.
148                With our test case above, as long as "cannot connect"
149                appears in the text of the string, the mock will issue a pass
150                to the unit tester.
151                The rest of the text does not matter.
152            </p>
153            <p>
154                The possible expectation classes are...
155                <table><tbody>
156                    <tr>
157<td><span class="new_code">AnythingExpectation</span></td>
158<td>Will always match</td>
159</tr>
160                    <tr>
161<td><span class="new_code">EqualExpectation</span></td>
162<td>An equality, rather than the stronger identity comparison</td>
163</tr>
164                    <tr>
165<td><span class="new_code">NotEqualExpectation</span></td>
166<td>An inequality comparison</td>
167</tr>
168                    <tr>
169<td><span class="new_code">IndenticalExpectation</span></td>
170<td>The default mock object check which must match exactly</td>
171</tr>
172                    <tr>
173<td><span class="new_code">NotIndenticalExpectation</span></td>
174<td>Inverts the mock object logic</td>
175</tr>
176                    <tr>
177<td><span class="new_code">WithinMarginExpectation</span></td>
178<td>Compares a value to within a margin</td>
179</tr>
180                    <tr>
181<td><span class="new_code">OutsideMarginExpectation</span></td>
182<td>Checks that a value is out side the margin</td>
183</tr>
184                    <tr>
185<td><span class="new_code">PatternExpectation</span></td>
186<td>Uses a Perl Regex to match a string</td>
187</tr>
188                    <tr>
189<td><span class="new_code">NoPatternExpectation</span></td>
190<td>Passes only if failing a Perl Regex</td>
191</tr>
192                    <tr>
193<td><span class="new_code">IsAExpectation</span></td>
194<td>Checks the type or class name only</td>
195</tr>
196                    <tr>
197<td><span class="new_code">NotAExpectation</span></td>
198<td>Opposite of the <span class="new_code">IsAExpectation</span>
199</td>
200</tr>
201                    <tr>
202<td><span class="new_code">MethodExistsExpectation</span></td>
203<td>Checks a method is available on an object</td>
204</tr>
205                </tbody></table>
206                Most take the expected value in the constructor.
207                The exceptions are the pattern matchers, which take a regular expression,
208                and the <span class="new_code">IsAExpectation</span> and <span class="new_code">NotAExpectation</span> which takes a type
209                or class name as a string.
210            </p>
211            <p>
212                Some examples...
213            </p>
214            <p>
215<pre>
216$mock-&gt;expectOnce('method', array(new IdenticalExpectation(14)));
217</pre>
218                This is the same as <span class="new_code">$mock-&gt;expectOnce('method', array(14))</span>.
219<pre>
220$mock-&gt;expectOnce('method', array(new EqualExpectation(14)));
221</pre>
222                This is different from the previous version in that the string
223                <span class="new_code">"14"</span> as a parameter will also pass.
224                Sometimes the additional type checks of SimpleTest are too restrictive.
225<pre>
226$mock-&gt;expectOnce('method', array(new AnythingExpectation(14)));
227</pre>
228                This is the same as <span class="new_code">$mock-&gt;expectOnce('method', array('*'))</span>.
229<pre>
230$mock-&gt;expectOnce('method', array(new IdenticalExpectation('*')));
231</pre>
232                This is handy if you want to assert a literal <span class="new_code">"*"</span>.
233<pre>
234new NotIdenticalExpectation(14)
235</pre>
236                This matches on anything other than integer 14.
237                Even the string <span class="new_code">"14"</span> would pass.
238<pre>
239new WithinMarginExpectation(14.0, 0.001)
240</pre>
241                This will accept any value from 13.999 to 14.001 inclusive.
242            </p>
243       
244        <p><a class="target" name="behaviour"><h2>Using expectations to control stubs</h2></a></p>
245            <p>
246                The expectation classes can be used not just for sending assertions
247                from mock objects, but also for selecting behaviour for the
248                <a href="mock_objects_documentation.html">mock objects</a>.
249                Anywhere a list of arguments is given, a list of expectation objects
250                can be inserted instead.
251            </p>
252            <p>
253                Suppose we want a mock authorisation server to simulate a successful login,
254                but only if it receives a valid session object.
255                We can do this as follows...
256<pre>
257Mock::generate('Authorisation');
258<strong>
259$authorisation = new MockAuthorisation();
260$authorisation-&gt;setReturnValue(
261        'isAllowed',
262        true,
263        array(new IsAExpectation('Session', 'Must be a session')));
264$authorisation-&gt;setReturnValue('isAllowed', false);</strong>
265</pre>
266                We have set the default mock behaviour to return false when
267                <span class="new_code">isAllowed</span> is called.
268                When we call the method with a single parameter that
269                is a <span class="new_code">Session</span> object, it will return true.
270                We have also added a second parameter as a message.
271                This will be displayed as part of the mock object
272                failure message if this expectation is the cause of
273                a failure.
274            </p>
275            <p>
276                This kind of sophistication is rarely useful, but is included for
277                completeness.
278            </p>
279       
280        <p><a class="target" name="extending"><h2>Creating your own expectations</h2></a></p>
281            <p>
282                The expectation classes have a very simple structure.
283                So simple that it is easy to create your own versions for
284                commonly used test logic.
285            </p>
286            <p>
287                As an example here is the creation of a class to test for
288                valid IP addresses.
289                In order to work correctly with the stubs and mocks the new
290                expectation class should extend
291                <span class="new_code">SimpleExpectation</span>...
292<pre>
293<strong>class ValidIp extends SimpleExpectation {
294   
295    function test($ip) {
296        return (ip2long($ip) != -1);
297    }
298   
299    function testMessage($ip) {
300        return "Address [$ip] should be a valid IP address";
301    }
302}</strong>
303</pre>
304                There are only two methods to implement.
305                The <span class="new_code">test()</span> method should
306                evaluate to true if the expectation is to pass, and
307                false otherwise.
308                The <span class="new_code">testMessage()</span> method
309                should simply return some helpful text explaining the test
310                that was carried out.
311            </p>
312            <p>
313                This class can now be used in place of the earlier expectation
314                classes.
315            </p>
316       
317        <p><a class="target" name="unit"><h2>Under the bonnet of the unit tester</h2></a></p>
318            <p>
319                The <a href="http://sourceforge.net/projects/simpletest/">SimpleTest unit testing framework</a>
320                also uses the expectation classes internally for the
321                <a href="unit_test_documentation.html">UnitTestCase class</a>.
322                We can also take advantage of these mechanisms to reuse our
323                homebrew expectation classes within the test suites directly.
324            </p>
325            <p>
326                The most crude way of doing this is to use the
327                <span class="new_code">SimpleTest::assert()</span> method to
328                test against it directly...
329<pre>
330<strong>class TestOfNetworking extends UnitTestCase {
331    ...
332    function testGetValidIp() {
333        $server = &amp;new Server();
334        $this-&gt;assert(
335                new ValidIp(),
336                $server-&gt;getIp(),
337                'Server IP address-&gt;%s');
338    }
339}</strong>
340</pre>
341                This is a little untidy compared with our usual
342                <span class="new_code">assert...()</span> syntax.
343            </p>
344            <p>
345                For such a simple case we would normally create a
346                separate assertion method on our test case rather
347                than bother using the expectation class.
348                If we pretend that our expectation is a little more
349                complicated for a moment, so that we want to reuse it,
350                we get...
351<pre>
352class TestOfNetworking extends UnitTestCase {
353    ...<strong>
354    function assertValidIp($ip, $message = '%s') {
355        $this-&gt;assert(new ValidIp(), $ip, $message);
356    }</strong>
357   
358    function testGetValidIp() {
359        $server = &amp;new Server();<strong>
360        $this-&gt;assertValidIp(
361                $server-&gt;getIp(),
362                'Server IP address-&gt;%s');</strong>
363    }
364}
365</pre>
366                It is unlikely we would ever need this degree of control
367                over the testing machinery.
368                It is rare to need the expectations for more than pattern
369                matching.
370                Also, complex expectation classes could make the tests
371                harder to read and debug.
372                These mechanisms are really of most use to authors of systems
373                that will extend the test framework to create their own tool set.
374            </p>
375       
376    </div>
377        References and related information...
378        <ul>
379<li>
380            SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
381        </li>
382<li>
383            SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
384        </li>
385<li>
386            The expectations mimic the constraints in <a href="http://www.jmock.org/">JMock</a>.
387        </li>
388<li>
389            <a href="http://simpletest.org/api/">Full API for SimpleTest</a>
390            from the PHPDoc.
391        </li>
392</ul>
393<div class="menu_back"><div class="menu">
394<a href="index.html">SimpleTest</a>
395                |
396                <a href="overview.html">Overview</a>
397                |
398                <a href="unit_test_documentation.html">Unit tester</a>
399                |
400                <a href="group_test_documentation.html">Group tests</a>
401                |
402                <a href="mock_objects_documentation.html">Mock objects</a>
403                |
404                <a href="partial_mocks_documentation.html">Partial mocks</a>
405                |
406                <a href="reporter_documentation.html">Reporting</a>
407                |
408                <span class="chosen">Expectations</span>
409                |
410                <a href="web_tester_documentation.html">Web tester</a>
411                |
412                <a href="form_testing_documentation.html">Testing forms</a>
413                |
414                <a href="authentication_documentation.html">Authentication</a>
415                |
416                <a href="browser_documentation.html">Scriptable browser</a>
417</div></div>
418<div class="copyright">
419            Copyright<br>Marcus Baker 2006
420        </div>
421</body>
422</html>
Note: See TracBrowser for help on using the repository browser.