- 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. - - -