PHPUnit袖珍指南之装置器

发表于:2007-06-21来源:作者:点击数: 标签:
编写测试最耗时的部分是边编写设置整个程序到达一个已知状态,而后在测试结束后返回到原始状态。这个已知状态叫做测试的装置器。 在例5中,装置器很简单,只是存储在变量$fixture中的数组。多数情况下,装置器会比简单数组复杂,设置代码也会相应增长。当你

   
  编写测试最耗时的部分是边编写设置整个程序到达一个已知状态,而后在测试结束后返回到原始状态。这个已知状态叫做测试的装置器。

  在例5中,装置器很简单,只是存储在变量$fixture中的数组。多数情况下,装置器会比简单数组复杂,设置代码也会相应增长。当你写几个类似的装置器时这个问题变得更糟糕。没有测试框架的帮助,我们不得不重复很多代码,为每个测试设置装置器。

  PHPUnit支持共享设置代码。在测试方法运行之前,模板类方法setUp( )会被调用。setUp( )用于创建要测试的对象,当测试方法结束运行时,无论成功失败,另一个模板方法tearDown( )会被调用。tearDown( )是用于清除测试用于的对象的。

  我们现在重构例5,使用setUp( )解决以前有的代码重复的问题。首先,我们定义变量$fixture的实例,用于替代局部方法中的变量。然后,我们将创建数组fixture的装置器放入方法setUp( )中。最后,我们将从测试方法中移除多余代码,使用新引进的变量实例,$this->fixture,使用assertEquals( )断言方法替代本地方法变量$fixture。

clearcase/" target="_blank" >cccccc width="90%" align=center bgColor=#e3e3e3 border=1>
<?php
require_once 'PHPUnit2/Framework/TestCase.php';
class ArrayTest extends PHPUnit2_Framework_TestCase {
 protected $fixture;
 protected function setUp( ) {
  // Create the Array fixture.
  $this->fixture = Array( );
 }

 public function testNewArrayIsEmpty( ) {
  // Assert that the size of the Array fixture is 0.
  $this->assertEquals(0, sizeof($this->fixture));
 }

 public function testArrayContainsAnElement( ) {
  // Add an element to the Array fixture.
  $this->fixture[] = 'Element';
  // Assert that the size of the Array fixture is 1.
  $this->assertEquals(1, sizeof($this->fixture));
 }
}
?>

  每个测试运行时,各调用setUp( )和tearDown( )一次。尽管在一个测试用例类中所有的测试方法只运行一次设置和解除代码,这看起来很简单,但这么做使得书写互相完全独立的测试相当困难。

  除了setUp( )和tearDown( )在每个测试中只运行一次外,每个测试在测试用例类的新实例中也只运行一次(参见本书后的PHPUnit的实现部分)。

  6-1. 多用setUp( ),少用tearDown( )

  理论上,setUp( )和tearDown( )是很好的对称关系,但实践中不是这样。如果你已经在setUp( )中分配了外部资源,如文件或socket,你只需要实现tearDown( )。 如果setUp() 只创造简单的PHP 对象,一般就可以忽略tearDown() 。 但是, 如果在setUp()创建了很多对象,你也许想要在tearDown()中用unset() 函数复位那些对象,这些对象会被垃圾收集器收集。测试用例对象的垃圾收集是不可预测的。

  6-2. 变量

  当有二个细微不同的设置过程的测试会怎么样? 有二种可能性:

  如果setUp() 代码只有少许不想同,将不同的代码移出setUp(),放入测试方法。

  如果setUp()完全不同,就要一个不同的测试用例类。命名不同的类名,体现在设置方法中。

  6-3. 套件级设定

  PHPUnit没有为套件的设定提供方便的支持。没有什么真正的原因要求在测试之间分享装置器,这种情况一般源于未解决的设计问题。

  在测试间共享装置器的一个好例子是数据库连接: 登录数据库一次,然后重复利用数据库连接,而不是为每个测试创建新连接。这使测试运行得更快。要实现这种情况,将数据库测试写在名为DatabaseTests得测试用例类中,并且包装测试套件在TestSetup 装饰器对象中,重载setUp(),实现打开数据库连接,在tearDown()中关闭连接,如例6。可以通过DatabaseTestSetup 装饰器调用,通过DatabaseTests运行测试,例如,PHPUnit 的命令行测试器通过phpunit DatabaseTestSetup运行。

  例6.书写套件层次的设置装饰器

<?php
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'PHPUnit2/Extensions/TestSetup.php';

class DatabaseTestSetup extends PHPUnit2_Extensions_TestSetup
{
 protected $connection = NULL;
 protected function setUp( ) {
  $this->connection = new PDO('mysql:host=wopr;dbname=test','root','');
 }

 protected function tearDown( ) {
  $this->connection = NULL;
 }

 public static function suite( ) {
  return new DatabaseTestSetup(new PHPUnit2_Framework_TestSuite('DatabaseTests'));
 }
}

?>

  怎么强调都不为过,在测试间共享装置器会减少测试的价值。隐藏的设计问题是,对象捆绑的太紧密。使用残根来书写测试能够解决隐藏的设计问题,得到更好的结果(参见本书后的残根部分),这比忽视改进设计机会,创建运行时有依赖关系的测试要好的多。

原文转自:http://www.ltesting.net