The implementation of PHPUnit is a bit unusual, using techniques that are difficult to maintain in ordinary application code. Understanding how PHPUnit runs your tests can help you write them.
A single test is represented by a
object and requires a
object to be run. The
object is passed to the
run() method, which runs the actual test
method and reports any exceptions to the
PHPUnit_Framework_TestResult object. This is an
idiom from the Smalltalk world called Collecting Parameter.
It suggests that when you need to collect results over several methods
(in our case the result of the serveral invocations of the
run() method for the various tests), you should add a
parameter to the method and pass an object that will collect the results
for you. See the article "JUnit: A
Cook's Tour" by Erich Gamma and Kent Beck [GammaBeck1999]
and "Smalltalk Best Practice Patterns" by Kent Beck [Beck1997].
To further understand how PHPUnit runs your tests, consider the test-case class in Example 19.1.
Example 19.1: The EmptyTest class
class EmptyTest extends PHPUnit_Framework_TestCase
private $emptyArray = array();
public function testSize()
public function testIsEmpty()
When the test is run, the first thing PHPUnit does is convert the
test class into a
PHPUnit_Framework_Test object --
two instances of
EmptyTest, as shown in
PHPUnit_Framework_TestSuite is run, it runs
each of the
EmptyTests in turn. Each runs its own
setUp() method, creating a fresh
$emptyArray for each test, as shown in
Figure 19.2. This way,
if one test modifies the array, the other test will not be affected. Even
changes to global and super-global (like
variables do not affect other tests.
In short, one test-case class results in a two-level tree of objects
when the tests are run. Each test method works with its own copy of the
objects created by
setUp(). The result is tests that
can run completely independently.
To run the test method itself, PHPUnit uses reflection to find the
method name in the instance variable
$name and invokes
it. This is another idiom, called Pluggable Selector,
that is commonly used in the Smalltalk world. Using a Pluggable Selector
makes the writing of tests simpler, but there is a tradeoff: you cannot
look at the code to decide whether a method is invoked, you have to look
at the data values at runtime.