迷惘的码农。
分类:
2008-04-07 18:01:53
PHPUnit的执行有点不常见,利用了在一般应用代码中难以维护的技术。理解PHPUnit如何运行你的测试有助于编写它们。
单个测试被表现为一个PHPUnit_Framework_Test
对象,而且需要一个PHPUnit_Framework_TestResult
对象来运行。PHPUnit_Framework_TestResult
对象被传入PHPUnit_Framework_Test
对象的run()
方法中,它运行实际的测试方法并向PHPUnit_Framework_TestResult
对象报告所有的异常。这是个来自Smalltalk世界的特性,称为聚集参数(Collecting Parameter)。它建议当你需要跨越多个方法收集结果时(在我们的案例中是若干对用于各种测试的run()
方法的调用结果),你应该像方法加入一个参数并传递一个将为你收集结果的对象。查阅Erich Gamma和Kent Beck的文章“JUnit: A Cook's Tour” 和Kent Beck的“Smalltalk Best Practice Patterns” 。
要进一步理解PHPUnit如何运行你的测试,考虑中的测试用例类。
范例 21.1: EmptyTest类
require_once 'PHPUnit/Framework.php';
class EmptyTest extends PHPUnit_Framework_TestCase
{
private $emptyArray = array();
public function testSize()
{
$this->assertEquals(0, sizeof($this->emptyArray));
}
public function testIsEmpty()
{
$this->assertTrue(empty($this->emptyArray));
}
}
?>
当测试运行时,PHPUnit做的第一件事情是把测试类转变为一个PHPUnit_Framework_Test
对象——此时,PHPUnit_Framework_TestSuite
包含两个EmptyTest
实例,如中所示。
图 21.1. 即将被运行的测试
当PHPUnit_Framework_TestSuite
运行时,它依次运行每个EmptyTest
。每次都运行它独有的setUp()
方法,为每个测试创建一个新的$emptyArray
,如中所示。使用这种方式,如果一个测试修改数组,其他测试不受影响。即使变为全局和超全局(如$_ENV
)变量也不影响其他测试。
图 21.2. 运行后的测试,各自带有自己特有的fixture
简而言之,测试运行时一个测试用例类导致一个两级的对象树。每个测试方法作用于其专有的通过setUp()
创建的对象拷贝。结果是测试能够完全独立地运行。
要运行测试方法自身,PHPUnit使用反射在实例变量$name
中查找方法名并调用它。这是另一个特性,称为插件式选择器(Pluggable Selector),通常用于Smalltalk世界。利用插件式选择器使得编写测试更简单,但也要付出代价:你不能根据代码来判定某方式是否被调用了,必须在运行时察看数据值。