Chapter 14. PHPUnit API

For most uses, PHPUnit has a simple API: subclass PHPUnit2_Framework_TestCase for your test cases and call assertTrue() or assertEquals(). However, for those of you who would like to look deeper into PHPUnit, here are all of its published methods and classes.

Overview

Most of the time, you will encounter five classes or interfaces when you are using PHPUnit:

PHPUnit2_Framework_Assert

A collection of static methods for checking actual values against expected values.

PHPUnit2_Framework_Test

The interface of all objects that act like tests.

PHPUnit2_Framework_TestCase

A single test.

PHPUnit2_Framework_TestSuite

A collection of tests.

PHPUnit2_Framework_TestResult

A summary of the results of running one or more tests.

Figure 14.1 shows the relationship of the five basic classes and interfaces in PHPUnit: PHPUnit2_Framework_Assert, PHPUnit2_Framework_Test, PHPUnit2_Framework_TestCase, PHPUnit2_Framework_TestSuite, and PHPUnit2_Framework_TestResult.

Figure 14.1. The five basic classes and interfaces in PHPUnit

The five basic classes and interfaces in PHPUnit

PHPUnit2_Framework_Assert

Most test cases written for PHPUnit are derived indirectly from the class PHPUnit2_Framework_Assert, which contains methods for automatically checking values and reporting discrepancies. The methods are declared static, so you can write design-by-contract style assertions in your methods and have them reported through PHPUnit (Example 14.1).

Example 14.1: Design-by-Contract Style Assertions

<?php
require_once 'PHPUnit2/Framework/Assert.php';
 
class Sample {
    public function aSampleMethod($object) {
        PHPUnit2_Framework_Assert::assertNotNull($object);
    }
}
 
$sample = new Sample;
$sample->aSampleMethod(NULL);
?>
Fatal error: Uncaught exception 'PHPUnit2_Framework_AssertionFailedError'
with message 'expected: <NOT NULL> but was: <NULL>'

Most of the time, though, you'll be checking the assertions inside of tests.

There are two variants of each of the assertion methods: one takes a message to be displayed with the error as a parameter, and one does not. The optional message is typically displayed when a failure is displayed, which can make debugging easier.

Example 14.2: Using assertions with messages

<?php
require_once 'PHPUnit2/Framework/TestCase.php';
 
class MessageTest extends PHPUnit2_Framework_TestCase {
    public function testMessage() {
        $this->assertTrue(FALSE, 'This is a custom message.');
    }
}
?>

The following example shows the output you get when you run the testMessage() test from Example 14.2, using assertions with messages:

phpunit MessageTest.php
PHPUnit 2.3.0 by Sebastian Bergmann.

F

Time: 0.102507
There was 1 failure:
1) testMessage(MessageTest)
This is a custom message.

FAILURES!!!
Tests run: 1, Failures: 1, Errors: 0, Incomplete Tests: 0.

Table 14.1 shows all the varieties of assertions.

Table 14.1. Assertions

AssertionMeaning
void assertTrue(Boolean $condition)Reports an error if $condition is FALSE.
void assertTrue(Boolean $condition, String $message)Reports an error identified by $message if $condition is FALSE.
void assertFalse(Boolean $condition)Reports an error if $condition is TRUE.
void assertFalse(Boolean $condition, String $message)Reports an error identified by $message if $condition is TRUE.
void assertNull(Mixed $variable)Reports an error if $variable is not NULL.
void assertNull(Mixed $variable, String $message)Reports an error identified by $message if $variable is not NULL.
void assertNotNull(Mixed $variable)Reports an error if $variable is NULL.
void assertNotNull(Mixed $variable, String $message)Reports an error identified by $message if $variable is NULL.
void assertSame(Object $expected, Object $actual)Reports an error if the two variables $expected and $actual do not reference the same object.
void assertSame(Object $expected, Object $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual do not reference the same object.
void assertSame(Mixed $expected, Mixed $actual)Reports an error if the two variables $expected and $actual do not have the same type and value.
void assertSame(Mixed $expected, Mixed $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual do not have the same type and value.
void assertNotSame(Object $expected, Object $actual)Reports an error if the two variables $expected and $actual reference the same object.
void assertNotSame(Object $expected, Object $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual reference the same object.
void assertNotSame(Mixed $expected, Mixed $actual)Reports an error if the two variables $expected and $actual have the same type and value.
void assertNotSame(Mixed $expected, Mixed $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual have the same type and value.
void assertEquals(Array $expected, Array $actual)Reports an error if the two arrays $expected and $actual are not equal.
void assertEquals(Array $expected, Array $actual, String $message)Reports an error identified by $message if the two arrays $expected and $actual are not equal.
void assertNotEquals(Array $expected, Array $actual)Reports an error if the two arrays $expected and $actual are equal.
void assertNotEquals(Array $expected, Array $actual, String $message)Reports an error identified by $message if the two arrays $expected and $actual are equal.
void assertEquals(Float $expected, Float $actual, Float $delta = 0)Reports an error if the two floats $expected and $actual are not within $delta of each other.
void assertEquals(Float $expected, Float $actual, String $message, Float $delta = 0)Reports an error identified by $message if the two floats $expected and $actual are not within $delta of each other.
void assertNotEquals(Float $expected, Float $actual, Float $delta = 0)Reports an error if the two floats $expected and $actual are within $delta of each other.
void assertNotEquals(Float $expected, Float $actual, String $message, Float $delta = 0)Reports an error identified by $message if the two floats $expected and $actual are within $delta of each other.
void assertEquals(String $expected, String $actual)Reports an error if the two strings $expected and $actual are not equal. The error is reported as the delta between the two strings.
void assertEquals(String $expected, String $actual, String $message)Reports an error identified by $message if the two strings $expected and $actual are not equal. The error is reported as the delta between the two strings.
void assertNotEquals(String $expected, String $actual)Reports an error if the two strings $expected and $actual are equal.
void assertNotEquals(String $expected, String $actual, String $message)Reports an error identified by $message if the two strings $expected and $actual are equal.
void assertEquals(Mixed $expected, Mixed $actual)Reports an error if the two variables $expected and $actual are not equal.
void assertEquals(Mixed $expected, Mixed $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual are not equal.
void assertNotEquals(Mixed $expected, Mixed $actual)Reports an error if the two variables $expected and $actual are equal.
void assertNotEquals(Mixed $expected, Mixed $actual, String $message)Reports an error identified by $message if the two variables $expected and $actual are equal.
void assertContains(Mixed $needle, Array $haystack)Reports an error if $needle is not an element of $haystack.
void assertContains(Mixed $needle, Array $haystack, String $message)Reports an error identified by $message if $needle is not an element of $haystack.
void assertNotContains(Mixed $needle, Array $haystack)Reports an error if $needle is an element of $haystack.
void assertNotContains(Mixed $needle, Array $haystack, String $message)Reports an error identified by $message if $needle is an element of $haystack.
void assertContains(Mixed $needle, Iterator $haystack)Reports an error if $needle is not an element of $haystack.
void assertContains(Mixed $needle, Iterator $haystack, String $message)Reports an error identified by $message if $needle is not an element of $haystack.
void assertNotContains(Mixed $needle, Iterator $haystack)Reports an error if $needle is an element of $haystack.
void assertNotContains(Mixed $needle, Iterator $haystack, String $message)Reports an error identified by $message if $needle is an element of $haystack.
void assertRegExp(String $pattern, String $string)Reports an error if $string does not match the regular expression $pattern.
void assertRegExp(String $pattern, String $string, String $message)Reports an error identified by $message if $string does not match the regular expression $pattern.
void assertNotRegExp(String $pattern, String $string)Reports an error if $string matches the regular expression $pattern.
void assertNotRegExp(String $pattern, String $string, String $message)Reports an error identified by $message if $string matches the regular expression $pattern.
void assertType(String $expected, Mixed $actual)Reports an error if the variable $actual is not of type $expected.
void assertType(String $expected, Mixed $actual, String $message)Reports an error identified by $message if the variable $actual is not of type $expected.
void assertNotType(String $expected, Mixed $actual)Reports an error if the variable $actual is of type $expected.
void assertNotType(String $expected, Mixed $actual, String $message)Reports an error identified by $message if the variable $actual is of type $expected.

You may find that you need other assertions than these to compare objects specific to your project. Create your own Assert class to contain these assertions to simplify your tests.

Failing assertions all call a single bottleneck method, fail(String $message), which throws an PHPUnit2_Framework_AssertionFailedError. There is also a variant which takes no parameters. Call fail() explicitly when your test encounters an error. The test for an expected exception is an example. Table 14.2 lists the bottlenext methods in PHPUnit.

Table 14.2. Bottleneck Methods

MethodMeaning
void fail()Reports an error.
void fail(String $message)Reports an error identified by $message.

PHPUnit2_Framework_Test

PHPUnit2_Framework_Test is the generic interface used by all objects that can act as tests. Implementors may represent one or more tests. The two methods are shown in Table 14.3.

Table 14.3. Implementor Methods

MethodMeaning
int countTestCases()Return the number of tests.
void run(PHPUnit2_Framework_TestResult $result)Run the tests and report the results on $result.

PHPUnit2_Framework_TestCase and PHPUnit2_Framework_TestSuite are the two most prominent implementors of PHPUnit2_Framework_Test. You can implement PHPUnit2_Framework_Test yourself. The interface is kept small intentionally so it will be easy to implement.

PHPUnit2_Framework_TestCase

Your test-case classes will inherit from PHPUnit2_Framework_TestCase. Most of the time, you will run tests from automatically created test suites. In this case, each of your tests should be represented by a method named test* (by convention).

PHPUnit2_Framework_TestCase implements PHPUnit2_Framework_Test::countTestCases() so that it always returns 1. The implementation of PHPUnit2_Framework_Test::run(PHPUnit2_Framework_TestResult $result) in this class runs setUp(), runs the test method, and then runs tearDown(), reporting any exceptions to the PHPUnit2_Framework_TestResult.

Table 14.4 shows the external protocol implemented by PHPUnit2_Framework_TestCase.

Table 14.4. TestCase external protocols

MethodMeaning
__construct()Creates a test case.
__construct(String $name)Creates a named test case. Names are used to print the test case and often as the name of the test method to be run by reflection.
String getName()Return the name of the test case.
void setName($name)Set the name of the test case.
PHPUnit2_Framework_TestResult run(PHPUnit2_Framework_TestResult $result)Convenience method to run the test case and report it in $result.
void runTest()Override with a testing method if you do not want the testing method to be invoked by reflection.

There are two template methods -- setUp() and tearDown() -- you can override to create and dispose of the objects against which you are going to test. Table 14.5 shows these methods.

Table 14.5. Template Methods

MethodMeaning
void setUp()Override to create objects against which to test. Each test that runs will be run in its own test case, and setUp() will be called separately for each one.
void tearDown()Override to dispose of objects no longer needed once the test has finished. In general, you only need to explicitly dispose of external resources (files or sockets, for example) in tearDown().

PHPUnit2_Framework_TestSuite

A PHPUnit2_Framework_TestSuite is a composite of PHPUnit2_Framework_Tests. At its simplest, it contains a bunch of test cases, all of which are run when the suite is run. Since it is a composite, however, a suite can contain suites which can contain suites and so on, making it easy to combine tests from various sources and run them together.

In addition to the PHPUnit2_Framework_Test protocol -- run(PHPUnit2_Framework_TestResult $result) and countTestCases() -- PHPUnit2_Framework_TestSuite contains protocol to create named or unnamed instances. Table 14.6 shows the instance creation protocol for PHPUnit2_Framework_TestSuite.

Table 14.6. Creating named or unnamed instances

MethodMeaning
__construct()Return an empty test suite.
__construct(String $theClass)Return a test suite containing an instance of the class named $theClass for each method in the class named test*. If no class of name $theClass exists an empty test suite named $theClass is returned.
__construct(String $theClass, String $name)Return a test suite named $name containing an instance of the class named $theClass for each method in the class named test*.
__construct(ReflectionClass $theClass)Return a test suite containing an instance of the class represented by $theClass for each method in the class named test*.
__construct(ReflectionClass $theClass, $name)Return a test suite named $name containing an instance of the class represented by $theClass for each method in the class named test*.
String getName()Return the name of the test suite.
void setName(String $name)Set the name of the test suite.

PHPUnit2_Framework_TestSuite also contains protocol for adding and retrieving PHPUnit2_Framework_Tests, as shown in Table 14.7.

Table 14.7. Protocol for adding and retrieving tests

MethodMeaning
void addTest(PHPUnit2_Framework_Test $test)Add $test to the suite.
void addTestFile(String $filename)Add the tests that are defined in the class(es) of a given sourcefile to the suite.
void addTestFiles(Array $filenames)Add the tests that are defined in the classes of the given sourcefiles to the suite.
int testCount()Return the number of tests directly (not recursively) in this suite.
PHPUnit2_Framework_Test[] tests()Return the tests directly in this suite.
PHPUnit2_Framework_Test testAt(int $index)Return the test at the $index.

Example 14.3 shows how to create and run a test suite.

Example 14.3: Creating and running a test suite

<?php
require_once 'PHPUnit2/Framework/TestSuite.php';
 
require_once 'ArrayTest.php';
 
// Create a test suite that contains the tests
// from the ArrayTest class.
$suite = new PHPUnit2_Framework_TestSuite('ArrayTest');
 
// Run the tests.
$suite->run();
?>

For an example on how to use PHPUnit2_Framework_TestSuite to hierarchically compose test cases let us look at PHPUnit's own test suite.

Example 14.4 shows a cut-down version of Tests/AllTests.php, Example 14.5 a cut-down version of Tests/Framework/AllTests.php.

Example 14.4: The AllTests class

<?php
if (!defined('PHPUnit2_MAIN_METHOD')) {
    define('PHPUnit2_MAIN_METHOD', 'AllTests::main');
}
 
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'PHPUnit2/TextUI/TestRunner.php';
 
require_once 'Framework/AllTests.php';
// ...
 
class AllTests {
    public static function main() {
        PHPUnit2_TextUI_TestRunner::run(self::suite());
    }
 
    public static function suite() {
        $suite = new PHPUnit2_Framework_TestSuite('PHPUnit');
 
        $suite->addTest(Framework_AllTests::suite());
        // ...
 
        return $suite;
    }
}
 
if (PHPUnit2_MAIN_METHOD == 'AllTests::main') {
    AllTests::main();
}
?>

Example 14.5: The Framework_AllTests class

<?php
if (!defined('PHPUnit2_MAIN_METHOD')) {
    define('PHPUnit2_MAIN_METHOD', 'Framework_AllTests::main');
}
 
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'PHPUnit2/TextUI/TestRunner.php';
 
require_once 'Framework/AssertTest.php';
// ...
 
class Framework_AllTests {
    public static function main() {
        PHPUnit2_TextUI_TestRunner::run(self::suite());
    }
 
    public static function suite() {
        $suite = new PHPUnit2_Framework_TestSuite('PHPUnit Framework');
 
        $suite->addTestSuite('Framework_AssertTest');
        // ...
 
        return $suite;
    }
}
 
if (PHPUnit2_MAIN_METHOD == 'Framework_AllTests::main') {
    Framework_AllTests::main();
}
?>

The Framework_AssertTest class is a standard test case that extends PHPUnit2_Framework_TestCase.

Running Tests/AllTests.php uses the TextUI test runner to run all tests while running Tests/Framework/AllTests.php runs only the tests for the PHPUnit2_Framework_* classes.

This example shows the PHPUnit test suite running:

php AllTests.php
PHPUnit 2.3.0 by Sebastian Bergmann.

.........................................
.........................................
.......

Time: 4.642600

OK (89 tests)

PHPUnit2_Framework_TestResult

While you are running all these tests, you need somewhere to store all the results: how many tests ran, which failed, and how long they took. PHPUnit2_Framework_TestResult collects these results. A single PHPUnit2_Framework_TestResult is passed around the whole tree of tests; when a test runs or fails, the fact is noted in the PHPUnit2_Framework_TestResult. At the end of the run, PHPUnit2_Framework_TestResult contains a summary of all the tests.

PHPUnit2_Framework_TestResult is also a subject than can be observed by other objects wanting to report test progress. For example, a graphical test runner might observe the PHPUnit2_Framework_TestResult and update a progress bar every time a test starts.

Table 14.8 summarizes the external protocols of PHPUnit2_Framework_TestResult.

Table 14.8. TestResult external protocols

MethodMeaning
void addError(PHPUnit2_Framework_Test $test, Exception $e)Record that running $test caused $e to be thrown unexpectedly.
void addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e)Record that running $test caused $e to be thrown unexpectedly.
PHPUnit2_Framework_TestFailure[] errors()Return the errors recorded.
PHPUnit2_Framework_TestFailure[] failures()Return the failures recorded.
PHPUnit2_Framework_TestFailure[] notImplemented()Return the incomplete test cases recorded.
int errorCount()Return the number of errors.
int failureCount()Return the number of failures.
int notImplementedCount()Return the number of incomplete test cases.
int runCount()Return the total number of test cases run.
Boolean wasSuccessfull()Return whether or not all tests ran successfully.
Boolean allCompletlyImplemented()Return whether or not all tests were completely implemented.
void collectCodeCoverageInformation(Boolean $flag)Enables or disables the collection of Code Coverage information.
Array getCodeCoverageInformation()Return the code coverage information collected.

If you want to register as an observer of a PHPUnit2_Framework_TestResult, you need to implement PHPUnit2_Framework_TestListener. To register, call addListener(), as shown in Table 14.9.

Table 14.9. TestResult and TestListener

MethodMeaning
void addListener(PHPUnit2_Framework_TestListener $listener)Register $listener to receive updates as results are recorded in the test result.
void removeListener(PHPUnit2_Framework_TestListener $listener)Unregister $listener from receiving updates.

Table 14.10 shows the methods that test listeners implement; also see Example 15.3.

Table 14.10. TestListener Callbacks

MethodMeaning
void addError(PHPUnit2_Framework_Test $test, Exception $e)$test has thrown $e.
void addFailure(PHPUnit2_Framework_Test $test, PHPUnit2_Framework_AssertionFailedError $e)$test has failed an assertion, throwing a kind of PHPUnit2_Framework_AssertionFailedError.
void addIncompleteTest(PHPUnit2_Framework_Test $test, Exception $e)$test is an incomplete test.
void startTestSuite(PHPUnit2_Framework_TestSuite $suite)$suite is about to be run.
void endTestSuite(PHPUnit2_Framework_TestSuite $suite)$suite has finished running.
void startTest(PHPUnit2_Framework_Test $test)$test is about to be run.
void endTest(PHPUnit2_Framework_Test $test)$test has finished running.

Package Structure

Many of the classes mentioned so far in this book come from PHPUnit2/Framework. Here are all the packages in PHPUnit:

  • PHPUnit2/Framework

    The basic classes in PHPUnit.

  • PHPUnit2/Extensions

    Extensions to the PHPUnit framework.

  • PHPUnit2/Runner

    Abstract support for running tests.

  • PHPUnit2/TextUI

    The text-based test runner.

  • PHPUnit2/Util

    Utility classes used by the other packages.