Приглашаем посетить
Гончаров (goncharov.lit-info.ru)

Chapter 14.  PHPUnit's Implementation

Previous
Table of Contents
Next

Chapter 14. PHPUnit's Implementation

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 PHPUnit2_Framework_Test object and requires a PHPUnit2_Framework_TestResult object to be run. The PHPUnit2_Framework_TestResult object is passed to the PHPUnit2_Framework_Test object's run( ) method, which runs the actual test method and reports any exceptions to the PHPUnit2_Framework_TestResult object. This is an idiom from the Smalltalk world called Collecting Parameter. It suggests that when you need to collect results from several methods (in our case the results of the several 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 (http://junit.sourceforge.net/doc/cookstour/cookstour.htm) and Smalltalk Best Practice Patterns by Kent Beck (Prentice Hall).

To further understand how PHPUnit runs your tests, consider the test-case class in Example 18.

Example 18. The EmptyTest class
<?php
require_once 'PHPUnit2/Framework/TestCase.php';

class EmptyTest extends PHPUnit2_Framework_TestCase {
  private $emptyArray = array( );

  public function testSize( ) {
    $this->assertEquals(0, sizeof($this->emptyArray));
  }

  public function testIsEmpty( ) {
    $this->assertTrue(empty($this->emptyArray));
  }
}
?>

When the test is run, the first thing PHPUnit does is convert the test class into a PHPUnit2_Framework_Test objecthere, a PHPUnit2_Framework_TestSuite containing two instances of EmptyTest, as shown in Figure 5.

Chapter 14.  PHPUnit's Implementation

Figure 1-5. Tests about to be run


When the PHPUnit2_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 6. This way, if one test modifies the list, the other test will not be affected. Even changes to global and super-global (such as $_ENV) 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 writing 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.

Chapter 14.  PHPUnit's Implementation

Figure 1-6. Tests after running, each with its own fixture



Previous
Table of Contents
Next