Changing the test display

The display component of SimpleTest is actually the part to be developed last. Some of the following section will change in the future and hopefully more sophisticated display components will be written, but in the meantime if a minimal display is not enough, here is how to roll your own.

I want to see the passes!

Oh all right then, here's how.

We have to subclass the attached display, which in our case is currently HtmlReporter. The HtmlReporter class is in the file simpletest/reporter.php and currently has the following interface...

class HtmlReporter extends TestDisplay {
    public TestHtmlDisplay() { ... }
    public void paintHeader(string $test_name) { ... }
    public void paintFooter(string $test_name) { ... }
    public void paintStart(string $test_name, $size) { ... }
    public void paintEnd(string $test_name, $size) { ... }
    public void paintFail(string $message) { ... }
    public void paintPass(string $message) { ... }
    protected string _getCss() { ... }
    public array getTestList() { ... }
    public integer getPassCount() { ... }
    public integer getFailCount() { ... }
    public integer getTestCaseCount() { ... }
    public integer getTestCaseProgress { ... }
}
Here is what the relevant methods mean. You can see the
whole list here if you are interested.

To show the passes we just need the paintPass() method to behave just like paintFail(). Of course we won't modify the original. We'll subclass.

A display subclass

Firstly we'll create a tests/show_passes.php file in our logging project and then place in it this empty class...

<?php
if (! defined('SIMPLE_TEST')) {
    define('SIMPLE_TEST', 'simpletest/');
}
require_once(SIMPLE_TEST . 'reporter.php');
    
class ShowPasses extends HtmlReporter {
        
    function ShowPasses() {
        $this->HtmlReporter();
    }
}
?>
A quick peruse of the
SimpleTest code base shows the paintFail() implementation at the time of writing to look like this...
function paintFail($message) {
    parent::paintFail($message);
    print "<span class=\"fail\">Fail</span>: ";
    $breadcrumb = $this->getTestList();
    array_shift($breadcrumb);
    print implode("->", $breadcrumb);
    print "->$message<br />\n";
}
Essentially it chains to the parent's version, which we have to do also to preserve house keeping, and then prints a breadcrumbs trail calculated from the current test list. It drops the top level tests name, though. As it is the same on every test that would be a little bit too much information. Transposing this to our new class...
class ShowPasses extends HtmlReporter {
    
    function ShowPasses() {
        $this->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";
    }
}
So far so good. Now to make use of our new class we have to modify our tests/all_tests.php file...
<?php
if (! defined('SIMPLE_TEST')) {
    define('SIMPLE_TEST', 'simpletest/');
}
require_once(SIMPLE_TEST . 'unit_tester.php');
require_once('show_passes.php');

$test = &new TestSuite('All tests');
$test->addTestFile('log_test.php');
$test->addTestFile('clock_test.php');
$test->run(new ShowPasses());
?>
We can run this to see the results of our handywork...

All tests

Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
Pass: log_test.php->Log class test->testcreatingnewfile->File created
Pass: clock_test.php->Clock class test->testclockadvance->Advancement
Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
3/3 test cases complete. 6 passes and 0 fails.
Nice, but no gold star. We have lost a little formatting here. The display does not have a CSS style for span.pass, but we can add this easily by overriding one more method...
class ShowPasses extends HtmlReporter {
    
    function ShowPasses() {
        $this->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; }';
    }
}
If you are adding the code as you go, you will see the style appended when you do view source on the test results page in your browser. To the eye the display itself should now look like this...

All tests

Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 1/] in [Test line 1]
Pass: log_test.php->Log class test->testappendingtofile->Expecting [/Test line 2/] in [Test line 2]
Pass: log_test.php->Log class test->testcreatingnewfile->Created before message
Pass: log_test.php->Log class test->testcreatingnewfile->File created
Pass: clock_test.php->Clock class test->testclockadvance->Advancement
Pass: clock_test.php->Clock class test->testclocktellstime->Now is the right time
3/3 test cases complete. 6 passes and 0 fails.
Some people definitely prefer to see the passes being added as they are working on code; the feeling that you are getting work done is nice after all. Once you have to scroll up and down the page to find failures though, you soon come to realise its dark side.

Try it both ways and see which you prefer. We'll leave it in for a bit anyhow when looking at the mock objects coming up. This is the first test tool that generates additional tests and it will be useful to see what is happening behind the scenes.

How to Change the display to show test passes.
Subclassing the HtmlReporter class.
The previous tutorial section was subclassing the test case.
This section is very specific to SimpleTest. If you use another tool you will want to skip this.