迷惘的码农。
分类:
2008-03-26 09:33:12
编写测试的一个最耗时部分是编写代码设置场景为已知状态以及在测试完成时将其还原为初始状态。这个已知状态称为测试的fixture。
在中,fixture只是存储在变量$fixture
中
的简单数组。然而,大多时候fixture比简单数组更复杂,因此相关装配代码的数量也随之增长。测试的实际内容迷失在这些装配fixture的干扰中
了。当你编写多个带有相似fixture的测试时,这个问题变得更糟。如果没有测试框架的帮助,我们就得为我们编写的每个测试复制那些装配fixture
的代码。
PHPUnit支持共享装配代码。在某个测试方法运行前,会调用一个名为setUp()
的模板方法。setUp()
是你创建测试所需对象的地方。一旦测试方法已经结束,不论成功还是失败,就会调用另一个称为tearDown()
的模板方法。tearDown()
是你清理测试用到的对象的地方。
我们现在可以重构,使用setUp()
消除之前的代码复制。首先声明实例变量,$fixture
,它将取代方法的局部变量。然后将数组
fixture的创建过程放入方法setUp()
中。最后,从测试方法中移除冗余代码,使用新引入的实例变量,$this->fixture
,取代用在断言方法assertEquals()
处的局部变量$fixture
。
范例 6.1: 使用setUp()创建数组fixture
require_once 'PHPUnit/Framework.php';
class ArrayTest extends PHPUnit_Framework_TestCase
{
protected $fixture;
protected function setUp()
{
// 创建数组fixture。
$this->fixture = array();
}
public function testNewArrayIsEmpty()
{
// 断言数组fixture的尺寸是0。
$this->assertEquals(0, sizeof($this->fixture));
}
public function testArrayContainsAnElement()
{
// 向数组fixture增加一个元素。
$this->fixture[] = 'Element';
// 断言数组fixture的尺寸是1。
$this->assertEquals(1, sizeof($this->fixture));
}
}
?>
运行每个测试方法都会分别调用setUp()
和tearDown()
一次。然而,对同一测试用例类中的所有测试方法只调用二者一次似乎比较解决,(但是)这么做会导致编写完全相互独立的测试异常困难。
不只是setUp()
和tearDown()
对每个测试方法都只运行一次,甚至所有测试方法都是运行于新的测试用例类上的(见)。
理论上setUp()
和tearDown()
是精确(一一)对应的,但事实上并非如此。实际上,只有你在setUp()
中分配了如文件或套接字等外部资源时,才需要实现tearDown()
。如果你的setUp()
只创建了普通得PHP对象,通常可以忽略tearDown()
。可是,如果在setUp()
中创建了很多对象,你可能想在tearDown()
中unset()
指向那些对象的变量以使它们可被垃圾回收。测试用例相关对象的垃圾回收并不是课预知的。
当两个测试的装配器(setup)只有些许的不同时会怎么样?有两种可能:
如果setUp()
的差异非常微小,把其中有区别的代码移到测试方法中。
如果某个setUp()
确实不同,你需要一个不同的测试用例类。根据装配器中的差异命名它。
很少需要在测试之间共享fixture,这其中的多数情形源于一个未解决的设计问题。
多个测试之间共享fixture的一个不错且有意义的例子是数据库连接:登陆一次,重用数据库连接而不是每个测试都创建新连接。这使得测试运行加快。
分别使用类PHPUnit_Framework_TestSuite
(见)的模板方法setUp()
和tearDown()
在测试套件的首个测试之前连接数据库以及套间的最后测试之后断开数据库连接。PHPUnit_Framework_TestSuite
对象的$sharedFixture
属性在PHPUnit_Framework_TestSuite
对象集合及PHPUnit_Framework_TestCase
对象中都可用。
范例 6.2: 在测试套件内的各测试间共享fixture
require_once 'PHPUnit/Framework.php';
class DatabaseTestSuite extends PHPUnit_Framework_TestSuite
{
protected function setUp()
{
$this->sharedFixture = new PDO(
'mysql:host=wopr;dbname=test',
'root',
''
);
}
protected function tearDown()
{
$this->sharedFixture = NULL;
}
}
?>
测试间共享fixture带来的测试价值的缩减怎么强调都不过分。潜在的设计问题是对象间并不是松散耦合的。利用存根(见)解决潜在的设计问题后再编写测试,比在测试间建立运行时依赖关系并错过改善设计的机会能得到更好的结果。(翻译是否有误? - 译注)