- SimpleTest pretty much follows the MVC pattern - (Model-View-Controller). - The reporter classes are the view and the model is your - test cases and their hiearchy. - The controller is mostly hidden from the user of - SimpleTest unless you want to change how the test cases - are actually run, in which case it is possible to - override the runner objects from within the test case. - As usual with MVC, the controller is mostly undefined - and there are other places to control the test run. -
- -
-
-Reporting results in HTML
-
-
- The default test display is minimal in the extreme. - It reports success and failure with the conventional red and - green bars and shows a breadcrumb trail of test groups - for every failed assertion. - Here's a fail... -
File test
- Fail: createnewfile->True assertion failed.-
File test
-- For web page based displays there is the - HtmlReporter class with the following - signature... -
-class HtmlReporter extends SimpleReporter { - public HtmlReporter($encoding) { ... } - public makeDry(boolean $is_dry) { ... } - public void paintHeader(string $test_name) { ... } - public void sendNoCacheHeaders() { ... } - public void paintFooter(string $test_name) { ... } - public void paintGroupStart(string $test_name, integer $size) { ... } - public void paintGroupEnd(string $test_name) { ... } - public void paintCaseStart(string $test_name) { ... } - public void paintCaseEnd(string $test_name) { ... } - public void paintMethodStart(string $test_name) { ... } - public void paintMethodEnd(string $test_name) { ... } - public void paintFail(string $message) { ... } - public void paintPass(string $message) { ... } - public void paintError(string $message) { ... } - public void paintException(string $message) { ... } - public void paintMessage(string $message) { ... } - public void paintFormattedMessage(string $message) { ... } - protected string _getCss() { ... } - public array getTestList() { ... } - public integer getPassCount() { ... } - public integer getFailCount() { ... } - public integer getExceptionCount() { ... } - public integer getTestCaseCount() { ... } - public integer getTestCaseProgress() { ... } -} -- Here is what some of these methods mean. First the display methods - that you will probably want to override... -
-
-
-
- HtmlReporter(string $encoding)
-
- is the constructor. - Note that the unit test sets up the link to the display - rather than the other way around. - The display is a mostly passive receiver of test events. - This allows easy adaption of the display for other test - systems beside unit tests, such as monitoring servers. - The encoding is the character encoding you wish to - display the test output in. - In order to correctly render debug output when - using the web tester, this should match the encoding - of the site you are trying to test. - The available character set strings are described in - the PHP html_entities() - function. -
- -
- void paintHeader(string $test_name)
-
- is called once at the very start of the test when the first - start event arrives. - The first start event is usually delivered by the top level group - test and so this is where $test_name - comes from. - It paints the page titles, CSS, body tag, etc. - It returns nothing (void). -
- -
- void paintFooter(string $test_name)
-
- Called at the very end of the test to close any tags opened - by the page header. - By default it also displays the red/green bar and the final - count of results. - Actually the end of the test happens when a test end event - comes in with the same name as the one that started it all - at the same level. - The tests nest you see. - Closing the last test finishes the display. -
- -
- void paintMethodStart(string $test_name)
-
- is called at the start of each test method. - The name normally comes from method name. - The other test start events behave the same way except - that the group test one tells the reporter how large - it is in number of held test cases. - This is so that the reporter can display a progress bar - as the runner churns through the test cases. -
- -
- void paintMethodEnd(string $test_name)
-
- backs out of the test started with the same name. -
- -
- void paintFail(string $message)
-
- paints a failure. - By default it just displays the word fail, a breadcrumbs trail - showing the current test nesting and the message issued by - the assertion. -
- -
- void paintPass(string $message)
-
- by default does nothing. -
- -
- string _getCss()
-
- Returns the CSS styles as a string for the page header - method. - Additional styles have to be appended here if you are - not overriding the page header. - You will want to use this method in an overriden page header - if you want to include the original CSS. -
-
-
-
-
- array getTestList()
-
- is the first convenience method for subclasses. - Lists the current nesting of the tests as a list - of test names. - The first, most deeply nested test, is first in the - list and the current test method will be last. -
- -
- integer getPassCount()
-
- returns the number of passes chalked up so far. - Needed for the display at the end. -
- -
- integer getFailCount()
-
- is likewise the number of fails so far. -
- -
- integer getExceptionCount()
-
- is likewise the number of errors so far. -
- -
- integer getTestCaseCount()
-
- is the total number of test cases in the test run. - This includes the grouping tests themselves. -
- -
- integer getTestCaseProgress()
-
- is the number of test cases completed so far. -
-
-class ShowPasses extends HtmlReporter { - - function paintPass($message) { - parent::paintPass($message); - print "&<span class=\"pass\">Pass</span>: "; - $breadcrumb = $this->getTestList(); - array_shift($breadcrumb); - print implode("->", $breadcrumb); - print "->$message<br />\n"; - } - - function _getCss() { - return parent::_getCss() . ' .pass { color: green; }'; - } -} -- -
- One method that was glossed over was the makeDry() - method. - If you run this method, with no parameters, on the reporter - before the test suite is run no actual test methods - will be called. - You will still get the events of entering and leaving the - test methods and test cases, but no passes or failures etc, - because the test code will not actually be executed. -
-- The reason for this is to allow for more sophistcated - GUI displays that allow the selection of individual test - cases. - In order to build a list of possible tests they need a - report on the test structure for drawing, say a tree view - of the test suite. - With a reporter set to dry run that just sends drawing events - this is easily accomplished. -
- - -- Rather than simply modifying the existing display, you might want to - produce a whole new HTML look, or even generate text or XML. - Rather than override every method in - HtmlReporter we can take one - step up the class hiearchy to SimpleReporter - in the simple_test.php source file. -
-- A do nothing display, a blank canvas for your own creation, would - be... -
-require_once('simpletest/simple_test.php'); - -class MyDisplay extends SimpleReporter { - - function paintHeader($test_name) { - } - - function paintFooter($test_name) { - } - - function paintStart($test_name, $size) { - parent::paintStart($test_name, $size); - } - - function paintEnd($test_name, $size) { - parent::paintEnd($test_name, $size); - } - - function paintPass($message) { - parent::paintPass($message); - } - - function paintFail($message) { - parent::paintFail($message); - } -} -- No output would come from this class until you add it. - - -
-
-The command line reporter
-
-
- SimpleTest also ships with a minimal command line reporter. - The interface mimics JUnit to some extent, but paints the - failure messages as they arrive. - To use the command line reporter simply substitute it - for the HTML version... -
-<?php - require_once('simpletest/unit_tester.php'); - require_once('simpletest/reporter.php'); - - $test = &new GroupTest('File test'); - $test->addTestFile('tests/file_test.php'); - $test->run(new TextReporter()); -?> -- Then invoke the test suite from the command line... -
-php file_test.php -- You will need the command line version of PHP installed - of course. - A passing test suite looks like this... -
-File test -OK -Test cases run: 1/1, Failures: 0, Exceptions: 0 -- A failure triggers a display like this... -
-File test -1) True assertion failed. - in createnewfile -FAILURES!!! -Test cases run: 1/1, Failures: 1, Exceptions: 0 -- -
- One of the main reasons for using a command line driven - test suite is of using the tester as part of some automated - process. - To function properly in shell scripts the test script should - return a non-zero exit code on failure. - If a test suite fails the value false - is returned from the SimpleTest::run() - method. - We can use that result to exit the script with the desired return - code... -
-<?php - require_once('simpletest/unit_tester.php'); - require_once('simpletest/reporter.php'); - - $test = &new GroupTest('File test'); - $test->addTestFile('tests/file_test.php'); - exit ($test->run(new TextReporter()) ? 0 : 1); -?> -- Of course we don't really want to create two test scripts, - a command line one and a web browser one, for each test suite. - The command line reporter includes a method to sniff out the - run time environment... -
-<?php - require_once('simpletest/unit_tester.php'); - require_once('simpletest/reporter.php'); - - $test = &new GroupTest('File test'); - $test->addTestFile('tests/file_test.php'); - if (TextReporter::inCli()) { - exit ($test->run(new TextReporter()) ? 0 : 1); - } - $test->run(new HtmlReporter()); -?> -- This is the form used within SimpleTest itself. - - - -
- SimpleTest ships with an XmlReporter class - used for internal communication. - When run the output looks like... -
-<?xml version="1.0"?> -<run> - <group size="4"> - <name>Remote tests</name> - <group size="4"> - <name>Visual test with 48 passes, 48 fails and 4 exceptions</name> - <case> - <name>testofunittestcaseoutput</name> - <test> - <name>testofresults</name> - <pass>This assertion passed</pass> - <fail>This assertion failed</fail> - </test> - <test> - ... - </test> - </case> - </group> - </group> -</run> -- You can make use of this format with the parser - supplied as part of SimpleTest itself. - This is called SimpleTestXmlParser and - resides in xml.php within the SimpleTest package... -
-<?php - require_once('simpletest/xml.php'); - - ... - $parser = &new SimpleTestXmlParser(new HtmlReporter()); - $parser->parse($test_output); -?> -- The $test_output should be the XML format - from the XML reporter, and could come from say a command - line run of a test case. - The parser sends events to the reporter just like any - other test run. - There are some odd occasions where this is actually useful. - -
- A problem with large test suites is thet they can exhaust - the default 8Mb memory limit on a PHP process. - By having the test groups output in XML and run in - separate processes, the output can be reparsed to - aggregate the results into a much smaller footprint top level - test. -
-- Because the XML output can come from anywhere, this opens - up the possibility of aggregating test runs from remote - servers. - A test case already exists to do this within the SimpleTest - framework, but it is currently experimental... -
-<?php - require_once('../remote.php'); - require_once('../reporter.php'); - - $test_url = ...; - $dry_url = ...; - - $test = &new GroupTest('Remote tests'); - $test->addTestCase(new RemoteTestCase($test_url, $dry_url)); - $test->run(new HtmlReporter()); -?> -- The RemoteTestCase takes the actual location - of the test runner, basically a web page in XML format. - It also takes the URL of a reporter set to do a dry run. - This is so that progress can be reported upward correctly. - The RemoteTestCase can be added to test suites - just like any other group test. - - -