<?xml version="1.0"?>
<!-- $Id: group_test_tutorial.xml 1954 2009-09-28 13:36:45Z arialdomartini $ -->
<page title="Grouping tests" here="Grouping tests">
    <long_title>
        PHP unit testing tutorial - Grouping together unit
        tests and examples of writing test cases
    </long_title>
    <content>
        <introduction>
            <p>
                Next up we will fill in some blanks and create a test suite.
            </p>
        </introduction>
        <section name="another" title="Another test">
            <p>
                Adding another test can be as simple as adding another method
                to a test case...
<php><![CDATA[
class TestOfLogging extends UnitTestCase {

    function testCreatingNewFile() {
        @unlink('../temp/test.log');
        $log = new Log('../temp/test.log');
        $this->assertFalse(file_exists('../temp/test.log'), 'Created before message');
        $log->message('Should write this to a file');
        $this->assertTrue(file_exists('../temp/test.log'), 'File created');<strong>
        @unlink('../temp/test.log');</strong>
    }
    <strong>
    function testSecondMessageIsAppended() {
        @unlink('../temp/test.log');
        $log = new Log('../temp/test.log');
        $log->message('Test line 1');
        $messages = file('../temp/test.log');
        $this->assertPattern('/Test line 1/', $messages[0]);
        $log->message('Test line 2');
        $messages = file('../temp/test.log');
        $this->assertPattern('/Test line 2/', $messages[1]);
        @unlink('../temp/test.log');
    }</strong>
}
]]></php>
                The <code>assertPattern()</code>
                test case method uses Perl style regular expressions for
                matching.
            </p>
            <p>
                All we are doing in this new test method is writing a line to a file and
                reading it back twice over.
                We simply want to confirm that the logger appends the
                text rather than writing over the old file.
            </p>
            <p>
                In fact this unit test actually passes straight away...
                <div class="demo">
                    <h1>Log class test</h1>
                    <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
                    <strong>4</strong> passes, <strong>0</strong> fails and <strong>0</strong> exceptions.</div>
                </div>
                The trouble is there is already a lot of repetition here,
                we have to delete the test file before and after every test.
            </p>
            <p>
                With outrageous plagarism from <a href="http://www.junit.org/">JUnit</a>,
                SimpleTest has <code>setUp()</code> and
                <code>tearDown()</code> methods
                which are run before and after every test respectively.
                File deletion is common to all the test methods so we
                should move that operation there.
            </p>
            <p>
                Our tests are green so we can refactor...
<php><![CDATA[
class TestOfLogging extends UnitTestCase {
<strong>
    function setUp() {
        @unlink('../temp/test.log');
    }

    function tearDown() {
        @unlink('../temp/test.log');
    }
</strong>
    function testCreatingNewFile() {
        $log = new Log('../temp/test.log');
        $this->assertFalse(file_exists('../temp/test.log'), 'Created before message');
        $log->message('Should write this to a file');
        $this->assertTrue(file_exists('../temp/test.log'), 'File created');
    }
    <strong>
    function testSecondMessageIsAppended() {
        $log = new Log('../temp/test.log');
        $log->message('Test line 1');
        $messages = file('../temp/test.log');
        $this->assertPattern('/Test line 1/', $messages[0]);
        $log->message('Test line 2');
        $messages = file('../temp/test.log');
        $this->assertPattern('/Test line 2/', $messages[1]);
    }
	</strong>
}
]]></php>
                The test stays green.
                We can add non-test methods to the test case as long as the method
                name does not start with the string &quot;test&quot;.
                Only the methods that start &quot;test&quot; are run.
                This allows further optional refactoring...
<php><![CDATA[
class TestOfLogging extends UnitTestCase {

    function setUp() {
        @unlink('../temp/test.log');
    }

    function tearDown() {
        @unlink('../temp/test.log');
    }
    <strong>
    function getFileLine($filename, $index) {
        $messages = file($filename);
        return $messages[$index];
    }
    </strong>
    function testCreatingNewFile() {
        $log = new Log('../temp/test.log');
        $this->assertFalse(file_exists('../temp/test.log'), 'Created before message');
        $log->message('Should write this to a file');
        $this->assertTrue(file_exists('../temp/test.log'), 'File created');
    }
    
    function testSecondMessageIsAppended() {
        $log = new Log('../temp/test.log');
        $log->message('Test line 1');<strong>
        $this->assertPattern('/Test line 1/', $this->getFileLine('../temp/test.log', 0));</strong>
        $log->message('Test line 2');<strong>
        $this->assertPattern('/Test line 2/', $this->getFileLine('../temp/test.log', 1));</strong>
    }
}
]]></php>
                It is a matter of taste whether you prefer this version
                to the previous one. There is a little more code, but
                the logic of the test is clearer.
            </p>
        </section>
        <section name="suite" title="A test suite">
            <p>
                A test case does not function alone for very long.
                When coding for real we usually want to run as many tests as
                quickly and as often as we can.
                This means grouping them together into test suites that
                could easily include every test in the application.
            </p>
            <p>
                Firstly we create a test suite called <em>all_tests.php</em>
                in the <em>tests</em> folder...
<php><![CDATA[
<?php
require_once(dirname(__FILE__) . '/simpletest/autorun.php');
<strong>require_once('log_test.php');

class AllTests extends TestSuite {
    function __construct() {
        parent::__construct();
        $this->addTest(new TestOfLogging());
    }
}
?></strong>
]]></php>
                We hardly notice the difference when things work...
                <div class="demo">
                    <h1>All tests</h1>
                    <div style="padding: 8px; margin-top: 1em; background-color: green; color: white;">1/1 test cases complete.
                    <strong>4</strong> passes and <strong>0</strong> fails.</div>
                </div>
                Adding new test cases is very straight forward.
            </p>
            <p>
                In the <a href="gain_control_tutorial.php">next page</a>
                we will add these more quickly.
            </p>
        </section>
    </content>
    <internal>
        <link>
            <a href="#another">Adding another test</a> to the test case
            and refactoring.
        </link>
        <link>
            The crude way to <a href="#suite">group unit tests</a> into a test suite.
        </link>
    </internal>
    <external>
        <link>
            <a href="gain_control_tutorial.php">Next</a> is controlling
            how the class under test interacts with the rest
            of the system.
        </link>
        <link>
            <a href="first_test_tutorial.php">Previous</a> is the creation
            of a first test.
        </link>
        <link>
            You need <a href="simple_test.php">SimpleTest</a> to run these examples.
        </link>
    </external>
    <meta>
        <keywords>
            software development,
            php programming,
            programming in php,
            test first,
            software development tools,
            php tutorial,
            free php scripts,
            architecture,
            php resources,
            mock objects,
            junit,
            php testing,
            unit test,
            phpunit,
            PHP unit testing
        </keywords>
    </meta>
</page>