SimpleTest for PHP group test documentation

# Group Test documentation

## Grouping tests

To run test cases as part of a group the test cases should really be placed in files without the runner code...

    <?php
        require_once('../classes/io.php');

        class FileTester extends UnitTestCase {
            ...
        }

        class SocketTester extends UnitTestCase {
            ...
        }
    ?>

As many cases as needed can appear in a single file. They should include any code they need, such as the library being tested, but none of the simple test libraries.

If you have extended any test cases, you can include them as well.

    <?php
        require_once('../classes/io.php');

        class MyFileTestCase extends UnitTestCase {
            ...
        }
        SimpleTest::ignore('MyFileTestCase');

        class FileTester extends MyFileTestCase {
            ...
        }

        class SocketTester extends UnitTestCase {
            ...
        }
    ?>

The FileTester class does not contain any actual tests, but is a base class for other test cases. For this reason we use the SimpleTestOptions::ignore() directive to tell the upcoming group test to ignore it. This directive can appear anywhere in the file and works when a whole file of test cases is loaded (see below). We will call this sample file_test.php.

Next we create a group test file, called say group_test.php. You will think of a better name I am sure. We will add the test file using a safe method...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('file_test.php');

        $test = &new GroupTest('All file tests');
        $test->addTestCase(new FileTestCase());
        $test->run(new HtmlReporter());
    ?>

This instantiates the test case before the test suite is run. This could get a little expensive with a large number of test cases, so another method is provided that will only instantiate the class when it is needed...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('file_test.php');

        $test = &new GroupTest('All file tests');
        $test->addTestClass('FileTestCase');
        $test->run(new HtmlReporter());
    ?>

The problem with this method is that for every test case that we add we will have to require_once() the test code file and manually instantiate each and every test case. We can save a lot of typing with...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');

        $test = &new GroupTest('All file tests');
        $test->addTestFile('file_test.php');
        $test->run(new HtmlReporter());
    ?&gt;

What happens here is that the GroupTest class has done the require_once() for us. It then checks to see if any new test case classes have been created by the new file and automatically adds them to the group test. Now all we have to do is add each new file.

There are two things that could go wrong and which require care...

1. The file could already have been parsed by PHP and so no new classes will have been added. You should make sure that the test cases are only included in this file and no others.
2. New test case extension classes that get included will be placed in the group test and run also. You will need to add a SimpleTestOptions::ignore() directive for these classes or make sure that they are included before the GroupTest::addTestFile() line.

## Higher groupings

The above method places all of the test cases into one large group. For larger projects though this may not be flexible enough; you may want to group the tests in all sorts of ways.

To get a more flexible group test we can subclass GroupTest and then instantiate it as needed...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');

        class FileGroupTest extends GroupTest {
            function FileGroupTest() {
                $this->GroupTest('All file tests');
                $this->addTestFile('file_test.php');
            }
        }
    ?>

This effectively names the test in the constructor and then adds our test cases and a single group below. Of course we can add more than one group at this point. We can now invoke the tests from a separate runner file...

    <?php
        require_once('file_group_test.php');

        $test = &new FileGroupTest();
        $test->run(new HtmlReporter());
    ?>

...or we can group them into even larger group tests...

    <?php
        require_once('file_group_test.php');

        $test = &new BigGroupTest('Big group');
        $test->addTestCase(new FileGroupTest());
        $test->addTestCase(...);
        $test->run(new HtmlReporter());
    ?>

If we still wish to run the original group test and we don't want all of these little runner files, we can put the test runner code around guard bars when we create each group.

    <?php
        class FileGroupTest extends GroupTest {
            function FileGroupTest() {
                $this->GroupTest('All file tests');
                $test->addTestFile('file_test.php');
            }
        }

        if (! defined('RUNNER')) {
            define('RUNNER', true);
            $test = &new FileGroupTest();
            $test->run(new HtmlReporter());
        }
    ?>

This approach requires the guard to be set when including the group test file, but this is still less hassle than lots of separate runner files. You include the same guard on the top level tests to make sure that run() will run once only from the top level script that has been invoked.

    <?php
        define('RUNNER', true);
        require_once('file_group_test.php');

        $test = &new BigGroupTest('Big group');
        $test->addTestCase(new FileGroupTest());
        $test->addTestCase(...);
        $test->run(new HtmlReporter());
    ?>

As with the normal test cases, a GroupTest can be loaded with the GroupTest::addTestFile() method.

    <?php
        define('RUNNER', true);

        $test = &new BigGroupTest('Big group');
        $test->addTestFile('file_group_test.php');
        $test->addTestFile(...);
        $test->run(new HtmlReporter());
    ?>

## Integrating legacy test cases

If you already have unit tests for your code or are extending external classes that have tests, it is unlikely that all of the test cases are in SimpleTest format. Fortunately it is possible to incorporate test cases from other unit testers directly into SimpleTest group tests.

Say we have the following PhpUnit test case in the file config_test.php...

    class ConfigFileTest extends TestCase {
        function ConfigFileTest() {
            $this->TestCase('Config file test');
        }

        function testContents() {
            $config = new ConfigFile('test.conf');
            $this->assertRegexp('/me/', $config->getValue('username'));
        }
    }

The group test can recognise this as long as we include the appropriate adapter class before we add the test file...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('simpletest/adapters/phpunit_test_case.php');

        $test = &new GroupTest('All file tests');
        $test->addTestFile('config_test.php');
        $test->run(new HtmlReporter());
    ?>

There are only two adapters, the other is for the PEAR 1.0 unit tester...

    <?php
        require_once('simpletest/unit_tester.php');
        require_once('simpletest/reporter.php');
        require_once('simpletest/adapters/pear_test_case.php');

        $test = &new GroupTest('All file tests');
        $test->addTestFile('some_pear_test_cases.php');
        $test->run(new HtmlReporter());
    ?>

The PEAR test cases can be freely mixed with SimpleTest ones even in the same test file, but you cannot use SimpleTest assertions in the legacy test case versions. This is done as a check that you are not accidently making your test cases completely dependent on SimpleTest. You may want to do a PEAR release of your library for example which would mean shipping it with valid PEAR::PhpUnit test cases.
Copyright
Marcus Baker, Jason Sweat, Perrick Penet 2004