+ The core system is a regression testing framework built around + test cases. + A sample test case looks like this... +
+class FileTestCase extends UnitTestCase { +} ++ If no test name is supplied when chaining the constructor then + the class name will be taken instead. + This will be the name displayed in the test results. + +
+ 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. + For example... +
+require_once('../classes/writer.php'); + +class FileTestCase extends UnitTestCase { + function FileTestCase() { + $this->UnitTestCase('File test'); + } + + 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'); + } +} ++ The constructor is optional and usually omitted. + Without a name, the class name is taken as the name of the test case. + +
+ Our only test method at the moment is testCreation() + where we check that a file has been created by our + Writer object. + We could have put the unlink() + code into this method as well, but by placing it in + setUp() and + tearDown() we can use it with + other test methods that we add. +
++ The setUp() method is run + just before each and every test method. + tearDown() is run just after + each and every test method. +
++ 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 setUp(), but + supplies additional hooks for library writers. +
++ The means of reporting test results (see below) are by a + visiting display class + that is notified by various assert...() + methods. + Here is the full list for the UnitTestCase + class, the default for SimpleTest... +
assertTrue($x) | Fail if $x is false | +
assertFalse($x) | Fail if $x is true | +
assertNull($x) | Fail if $x is set | +
assertNotNull($x) | Fail if $x not set | +
assertIsA($x, $t) | Fail if $x is not the class or type $t | +
assertNotA($x, $t) | Fail if $x is of the class or type $t | +
assertEqual($x, $y) | Fail if $x == $y is false | +
assertNotEqual($x, $y) | Fail if $x == $y is true | +
assertIdentical($x, $y) | Fail if $x == $y is false or a type mismatch | +
assertNotIdentical($x, $y) | Fail if $x == $y is true and types match | +
assertReference($x, $y) | Fail unless $x and $y are the same variable | +
assertCopy($x, $y) | Fail if $x and $y are the same variable | +
assertWantedPattern($p, $x) | Fail unless the regex $p matches $x | +
assertNoUnwantedPattern($p, $x) | Fail if the regex $p matches $x | +
assertNoErrors() | Fail if any PHP error occoured | +
assertError($x) | Fail if no PHP error or incorrect message | +
assertErrorPattern($p) | Fail unless the error matches the regex $p | +
+ Some examples... +
+$variable = null; +$this->assertNull($variable, 'Should be cleared'); ++ ...will pass and normally show no message. + If you have + set up the tester to display passes + as well then the message will be displayed as is. +
+$this->assertIdentical(0, false, 'Zero is not false [%s]'); ++ 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. + This also allows us to nest test messages. +
+$a = 1; +$b = $a; +$this->assertReference($a, $b); ++ Will fail as the variable $a is a copy of $b. +
+$this->assertWantedPattern('/hello/i', 'Hello world'); ++ This will pass as using a case insensitive match the string + hello is contained in Hello world. +
+trigger_error('Disaster'); +trigger_error('Catastrophe'); +$this->assertError(); +$this->assertError('Catastrophe'); +$this->assertNoErrors(); ++ This one takes some explanation as in fact they all pass! + +
+ PHP errors in SimpleTest are trapped and placed in a queue. + Here the first error check catches the "Disaster" + message without checking the text and passes. + This removes the error from the queue. + The next error check tests not only the existence of the error, + but also the text which here matches so another pass. + With the queue now empty the last test will pass as well. + If any unchecked errors are left at the end of a test method then + an exception will be reported in the test. + Note that SimpleTest cannot catch compile time PHP errors. +
++ The test cases also have some convenience methods for debugging + code or extending the suite... +
setUp() | Runs this before each test method | +
tearDown() | Runs this after each test method | +
pass() | Sends a test pass | +
fail() | Sends a test failure | +
error() | Sends an exception event | +
sendMessage() | Sends a status message to those displays that support it | +
signal($type, $payload) | Sends a user defined message to the test reporter | +
dump($var) | Does a formatted print_r() for quick and dirty debugging | +
swallowErrors() | Clears the error queue | +
+ Of course additional test methods can be added to create + specific types of test case too so as to extend framework... +
+require_once('simpletest/unit_tester.php'); + +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')); + } +} ++ Here the SimpleTest library is held in a folder called + simpletest that is local. + Substitute your own path for this. + +
+ This new case can be now be inherited just like + a normal test case... +
+class FileTestCase extends FileTester { + + function setUp() { + @unlink('../temp/test.txt'); + } + + function tearDown() { + @unlink('../temp/test.txt'); + } + + function testCreation() { + $writer = &new FileWriter('../temp/test.txt'); + $writer->write('Hello'); + $this->assertFileExists('../temp/test.txt'); + } +} ++ +
+ If you want a test case that does not have all of the + UnitTestCase assertions, + only your own and assertTrue(), + you need to extend the SimpleTestCase + class instead. + It is found in simple_test.php rather than + unit_tester.php. + See later if you + want to incorporate other unit tester's + test cases in your test suites. +
+ +
+
+Running a single test case
+
+
+ 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. + Here is the scaffolding needed to run the a lone test case... +
+<?php + require_once('simpletest/unit_tester.php'); + require_once('simpletest/reporter.php'); + require_once('../classes/writer.php'); + + class FileTestCase extends UnitTestCase { + function FileTestCase() { + $this->UnitTestCase('File test'); + } + } + + $test = &new FileTestCase(); + $test->run(new HtmlReporter()); +?> ++ This script will run as is, but will output zero passes + and zero failures until test methods are added. + + +