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
|
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>SimpleTest for PHP regression test documentation</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>
|
<span class="chosen">Unit tester</span>
|
<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>PHP Unit Test documentation</h1>
This page...
<ul>
<li>
<a href="#unit">Unit test cases</a> and basic assertions.
</li>
<li>
<a href="#extending_unit">Extending test cases</a> to
customise them for your own project.
</li>
<li>
<a href="#running_unit">Running a single case</a> as
a single script.
</li>
</ul>
<div class="content">
<p><a class="target" name="unit"><h2>Unit test cases</h2></a></p>
<p>
The core system is a regression testing framework built around
test cases.
A sample test case looks like this...
<pre>
<strong>class FileTestCase extends UnitTestCase {
}</strong>
</pre>
Actual tests are added as methods in the test case whose names
by default start with the string "test" and
when the test case is invoked all such methods are run in
the order that PHP introspection finds them.
As many test methods can be added as needed.
</p>
<p>
For example...
<pre>
require_once('simpletest/autorun.php');
require_once('../classes/writer.php');
class FileTestCase extends UnitTestCase {
function FileTestCase() {
$this->UnitTestCase('File test');
}<strong>
function setUp() {
@unlink('../temp/test.txt');
}
function tearDown() {
@unlink('../temp/test.txt');
}
function testCreation() {
$writer = &new FileWriter('../temp/test.txt');
$writer->write('Hello');
$this->assertTrue(file_exists('../temp/test.txt'), 'File created');
}</strong>
}
</pre>
The constructor is optional and usually omitted.
Without a name, the class name is taken as the name of the test case.
</p>
<p>
Our only test method at the moment is <span class="new_code">testCreation()</span>
where we check that a file has been created by our
<span class="new_code">Writer</span> object.
We could have put the <span class="new_code">unlink()</span>
code into this method as well, but by placing it in
<span class="new_code">setUp()</span> and
<span class="new_code">tearDown()</span> we can use it with
other test methods that we add.
</p>
<p>
The <span class="new_code">setUp()</span> method is run
just before each and every test method.
<span class="new_code">tearDown()</span> is run just after
each and every test method.
</p>
<p>
You can place some test case set up into the constructor to
be run once for all the methods in the test case, but
you risk test inteference that way.
This way is slightly slower, but it is safer.
Note that if you come from a JUnit background this will not
be the behaviour you are used to.
JUnit surprisingly reinstantiates the test case for each test
method to prevent such interference.
SimpleTest requires the end user to use <span class="new_code">setUp()</span>, but
supplies additional hooks for library writers.
</p>
<p>
The means of reporting test results (see below) are by a
visiting display class
that is notified by various <span class="new_code">assert...()</span>
methods.
Here is the full list for the <span class="new_code">UnitTestCase</span>
class, the default for SimpleTest...
<table><tbody>
<tr>
<td><span class="new_code">assertTrue($x)</span></td>
<td>Fail if $x is false</td>
</tr>
<tr>
<td><span class="new_code">assertFalse($x)</span></td>
<td>Fail if $x is true</td>
</tr>
<tr>
<td><span class="new_code">assertNull($x)</span></td>
<td>Fail if $x is set</td>
</tr>
<tr>
<td><span class="new_code">assertNotNull($x)</span></td>
<td>Fail if $x not set</td>
</tr>
<tr>
<td><span class="new_code">assertIsA($x, $t)</span></td>
<td>Fail if $x is not the class or type $t</td>
</tr>
<tr>
<td><span class="new_code">assertNotA($x, $t)</span></td>
<td>Fail if $x is of the class or type $t</td>
</tr>
<tr>
<td><span class="new_code">assertEqual($x, $y)</span></td>
<td>Fail if $x == $y is false</td>
</tr>
<tr>
<td><span class="new_code">assertNotEqual($x, $y)</span></td>
<td>Fail if $x == $y is true</td>
</tr>
<tr>
<td><span class="new_code">assertWithinMargin($x, $y, $m)</span></td>
<td>Fail if abs($x - $y) < $m is false</td>
</tr>
<tr>
<td><span class="new_code">assertOutsideMargin($x, $y, $m)</span></td>
<td>Fail if abs($x - $y) < $m is true</td>
</tr>
<tr>
<td><span class="new_code">assertIdentical($x, $y)</span></td>
<td>Fail if $x == $y is false or a type mismatch</td>
</tr>
<tr>
<td><span class="new_code">assertNotIdentical($x, $y)</span></td>
<td>Fail if $x == $y is true and types match</td>
</tr>
<tr>
<td><span class="new_code">assertReference($x, $y)</span></td>
<td>Fail unless $x and $y are the same variable</td>
</tr>
<tr>
<td><span class="new_code">assertClone($x, $y)</span></td>
<td>Fail unless $x and $y are identical copies</td>
</tr>
<tr>
<td><span class="new_code">assertPattern($p, $x)</span></td>
<td>Fail unless the regex $p matches $x</td>
</tr>
<tr>
<td><span class="new_code">assertNoPattern($p, $x)</span></td>
<td>Fail if the regex $p matches $x</td>
</tr>
<tr>
<td><span class="new_code">expectError($x)</span></td>
<td>Swallows any upcoming matching error</td>
</tr>
<tr>
<td><span class="new_code">assert($e)</span></td>
<td>Fail on failed <a href="expectation_documentation.html">expectation</a> object $e</td>
</tr>
</tbody></table>
All assertion methods can take an optional description as a
last parameter.
This is to label the displayed result with.
If omitted a default message is sent instead, which is usually
sufficient.
This default message can still be embedded in your own message
if you include "%s" within the string.
All the assertions return true on a pass or false on failure.
</p>
<p>
Some examples...
<pre>
$variable = null;
<strong>$this->assertNull($variable, 'Should be cleared');</strong>
</pre>
...will pass and normally show no message.
If you have
<a href="http://www.lastcraft.com/display_subclass_tutorial.php">set up the tester to display passes</a>
as well then the message will be displayed as is.
<pre>
<strong>$this->assertIdentical(0, false, 'Zero is not false [%s]');</strong>
</pre>
This will fail as it performs a type
check, as well as a comparison, between the two values.
The "%s" part is replaced by the default
error message that would have been shown if we had not
supplied our own.
<pre>
$a = 1;
$b = $a;
<strong>$this->assertReference($a, $b);</strong>
</pre>
Will fail as the variable <span class="new_code">$a</span> is a copy of <span class="new_code">$b</span>.
<pre>
<strong>$this->assertPattern('/hello/i', 'Hello world');</strong>
</pre>
This will pass as using a case insensitive match the string
<span class="new_code">hello</span> is contained in <span class="new_code">Hello world</span>.
<pre>
<strong>$this->expectError();</strong>
trigger_error('Catastrophe');
</pre>
Here the check catches the "Catastrophe"
message without checking the text and passes.
This removes the error from the queue.
<pre>
<strong>$this->expectError('Catastrophe');</strong>
trigger_error('Catastrophe');
</pre>
The next error check tests not only the existence of the error,
but also the text which, here matches so another pass.
If any unchecked errors are left at the end of a test method then
an exception will be reported in the test.
</p>
<p>
Note that SimpleTest cannot catch compile time PHP errors.
</p>
<p>
The test cases also have some convenience methods for debugging
code or extending the suite...
<table><tbody>
<tr>
<td><span class="new_code">setUp()</span></td>
<td>Runs this before each test method</td>
</tr>
<tr>
<td><span class="new_code">tearDown()</span></td>
<td>Runs this after each test method</td>
</tr>
<tr>
<td><span class="new_code">pass()</span></td>
<td>Sends a test pass</td>
</tr>
<tr>
<td><span class="new_code">fail()</span></td>
<td>Sends a test failure</td>
</tr>
<tr>
<td><span class="new_code">error()</span></td>
<td>Sends an exception event</td>
</tr>
<tr>
<td><span class="new_code">signal($type, $payload)</span></td>
<td>Sends a user defined message to the test reporter</td>
</tr>
<tr>
<td><span class="new_code">dump($var)</span></td>
<td>Does a formatted <span class="new_code">print_r()</span> for quick and dirty debugging</td>
</tr>
</tbody></table>
</p>
<p><a class="target" name="extending_unit"><h2>Extending test cases</h2></a></p>
<p>
Of course additional test methods can be added to create
specific types of test case, so as to extend framework...
<pre>
require_once('simpletest/autorun.php');
<strong>
class FileTester extends UnitTestCase {
function FileTester($name = false) {
$this->UnitTestCase($name);
}
function assertFileExists($filename, $message = '%s') {
$this->assertTrue(
file_exists($filename),
sprintf($message, 'File [$filename] existence check'));
}</strong>
}
</pre>
Here the SimpleTest library is held in a folder called
<em>simpletest</em> that is local.
Substitute your own path for this.
</p>
<p>
To prevent this test case being run accidently, it is
advisable to mark it as <span class="new_code">abstract</span>.
</p>
<p>
Alternatively you could add a
<span class="new_code">SimpleTestOptions::ignore('FileTester');</span>
directive in your code.
</p>
<p>
This new case can be now be inherited just like
a normal test case...
<pre>
class FileTestCase extends <strong>FileTester</strong> {
function setUp() {
@unlink('../temp/test.txt');
}
function tearDown() {
@unlink('../temp/test.txt');
}
function testCreation() {
$writer = &new FileWriter('../temp/test.txt');
$writer->write('Hello');<strong>
$this->assertFileExists('../temp/test.txt');</strong>
}
}
</pre>
</p>
<p>
If you want a test case that does not have all of the
<span class="new_code">UnitTestCase</span> assertions,
only your own and a few basics,
you need to extend the <span class="new_code">SimpleTestCase</span>
class instead.
It is found in <em>simple_test.php</em> rather than
<em>unit_tester.php</em>.
See <a href="group_test_documentation.html">later</a> if you
want to incorporate other unit tester's
test cases in your test suites.
</p>
<p><a class="target" name="running_unit"><h2>Running a single test case</h2></a></p>
<p>
You won't often run single test cases except when bashing
away at a module that is having difficulty, and you don't
want to upset the main test suite.
With <em>autorun</em> no particular scaffolding is needed,
just launch your particular test file and you're ready to go.
</p>
<p>
You can even decide which reporter (for example,
<span class="new_code">TextReporter</span> or <span class="new_code">HtmlReporter</span>)
you prefer for a specific file when launched on its own...
<pre>
<?php
require_once('simpletest/autorun.php');<strong>
SimpleTest :: prefer(new TextReporter());</strong>
require_once('../classes/writer.php');
class FileTestCase extends UnitTestCase {
...
}
?>
</pre>
This script will run as is, but of course will output zero passes
and zero failures until test methods are added.
</p>
</div>
References and related information...
<ul>
<li>
SimpleTest project page on <a href="http://sourceforge.net/projects/simpletest/">SourceForge</a>.
</li>
<li>
SimpleTest download page on <a href="http://www.lastcraft.com/simple_test.php">LastCraft</a>.
</li>
<li>
<a href="http://simpletest.org/api/">Full API for SimpleTest</a>
from the PHPDoc.
</li>
</ul>
<div class="menu_back"><div class="menu">
<a href="index.html">SimpleTest</a>
|
<a href="overview.html">Overview</a>
|
<span class="chosen">Unit tester</span>
|
<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>
|