Chinaunix首页 | 论坛 | 博客
  • 博客访问: 683995
  • 博文数量: 132
  • 博客积分: 10060
  • 博客等级: 上将
  • 技术积分: 1732
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-21 12:35
个人简介

迷惘的码农。

文章分类

全部博文(132)

文章存档

2013年(1)

2011年(2)

2010年(9)

2009年(41)

2008年(79)

我的朋友

分类:

2008-04-08 11:37:15

第 23 章 扩展PHPUnit

PHPUnit能以各种不同的方式扩展,以使编写测试更容易并且定制来自运行测试的反馈。这是扩展PHPUnit的共同起点。

子类化PHPUnit_Framework_TestCase

在抽象子类PHPUnit_Framework_TestCase中编写工具方法并从该类得到你的测试用例类。这是扩展PHPUnit的最简单的方法之一。

断言类

编写你自己的类,它们带有专用于你的目的的断言。

子类化PHPUnit_Extensions_TestDecorator

你可以在PHPUnit_Extensions_TestDecorator的子类中中封装测试用例或测试套件,并使用装饰者(Decorator)模式在测试运行前后执行某些动作。

PHPUnit自带两个具体的测试装饰者:PHPUnit_Extensions_RepeatedTestPHPUnit_Extensions_TestSetup。前一个用于重复运行一个测试,并且只当所有迭代都成功时才算成功。后面一个在中讨论过。

显示一个删节版的PHPUnit_Extensions_RepeatedTest测试装饰者,例解如何编写自己的测试装饰者。

范例 23.1: RepeatedTest装饰者


require_once 'PHPUnit/Extensions/TestDecorator.php';
 
class PHPUnit_Extensions_RepeatedTest extends PHPUnit_Extensions_TestDecorator
{
    private $timesRepeat = 1;
 
    public function __construct(PHPUnit_Framework_Test $test, $timesRepeat = 1)
    {
        parent::__construct($test);
 
        if (is_integer($timesRepeat) &&
            $timesRepeat >= 0) {
            $this->timesRepeat = $timesRepeat;
        }
    }
 
    public function count()
    {
        return $this->timesRepeat * $this->test->count();
    }
 
    public function run(PHPUnit_Framework_TestResult $result = NULL)
    {
        if ($result === NULL) {
            $result = $this->createResult();
        }
 
        for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) {
            $this->test->run($result);
        }
 
        return $result;
    }
}
?>

实现PHPUnit_Framework_Test

接口PHPUnit_Framework_Test很有限且易于实现。你能够编写一个比PHPUnit_Framework_TestCase简单而且运行(比如)数据驱动测试PHPUnit_Framework_Test的实现。

显示一个数据驱动的测试用例类,用来比较来自文件的逗号分隔的值(CSV)。这种文件的每一行类似foo;bar,其第一个值是我们期望的,第二个值是实际值。

范例 23.2: 一个数据驱动测试


require_once 'PHPUnit/Framework.php';
require_once 'PHPUnit/Util/Timer.php';
require_once 'PHPUnit/TextUI/TestRunner.php';
 
class DataDrivenTest implements PHPUnit_Framework_Test
{
    private $lines;
 
    public function __construct($dataFile)
    {
        $this->lines = file($dataFile);
    }
 
    public function count()
    {
        return 1;
    }
 
    public function run(PHPUnit_Framework_TestResult $result = NULL)
    {
        if ($result === NULL) {
            $result = new PHPUnit_Framework_TestResult;
        }
 
        foreach ($this->lines as $line) {
            $result->startTest($this);
            PHPUnit_Util_Timer::start();
 
            list($expected, $actual) = explode(';', $line);
 
            try {
                PHPUnit_Framework_Assert::assertEquals(trim($expected), trim($actual));
            }
 
            catch (PHPUnit_Framework_AssertionFailedError $e) {
                $result->addFailure($this, $e, PHPUnit_Util_Timer::stop());
            }
 
            catch (Exception $e) {
                $result->addError($this, $e, PHPUnit_Util_Timer::stop());
            }
 
            $result->endTest($this, PHPUnit_Util_Timer::stop());
        }
 
        return $result;
    }
}
 
$test = new DataDrivenTest('data_file.csv');
$result = PHPUnit_TextUI_TestRunner::run($test);
?>
PHPUnit 3.2.10 by Sebastian Bergmann.

.F

Time: 0 seconds

There was 1 failure:

1) DataDrivenTest
Failed asserting that two strings are equal.
expected string
difference < x>
got string
/home/sb/DataDrivenTest.php:32
/home/sb/DataDrivenTest.php:53

FAILURES!
Tests: 2, Failures: 1.

子类化PHPUnit_Framework_TestResult

通过向run()方法传入一个特殊用途的PHPUnit_Framework_TestResult对象,你能改变测试运行的方式和收集的结果数据。

实现PHPUnit_Framework_TestListener

要定制PHPUnit_Framework_TestResult,没必要编写它的整个子类。大多时候,实现一个新PHPUnit_Framework_TestListener(见)并在运行测试前附在PHPUnit_Framework_TestResult对象上就够了。

显示PHPUnit_Framework_TestListener接口的一个简单实现。

范例 23.3:一个简单的测试监听器


require_once 'PHPUnit/Framework.php';
 
class SimpleTestListener
implements PHPUnit_Framework_TestListener
{
  public function
  addError(PHPUnit_Framework_Test $test,
           Exception $e,
           $time)
  {
    printf(
      "Error while running test '%s'.\n",
      $test->getName()
    );
  }
 
  public function
  addFailure(PHPUnit_Framework_Test $test,
             PHPUnit_Framework_AssertionFailedError $e,
             $time)
  {
    printf(
      "Test '%s' failed.\n",
      $test->getName()
    );
  }
 
  public function
  addIncompleteTest(PHPUnit_Framework_Test $test,
                    Exception $e,
                    $time)
  {
    printf(
      "Test '%s' is incomplete.\n",
      $test->getName()
    );
  }
 
  public function
  addSkippedTest(PHPUnit_Framework_Test $test,
                 Exception $e,
                 $time)
  {
    printf(
      "Test '%s' has been skipped.\n",
      $test->getName()
    );
  }
 
  public function startTest(PHPUnit_Framework_Test $test)
  {
    printf(
      "Test '%s' started.\n",
      $test->getName()
    );
  }
 
  public function endTest(PHPUnit_Framework_Test $test, $time)
  {
    printf(
      "Test '%s' ended.\n",
      $test->getName()
    );
  }
 
  public function
  startTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
    printf(
      "TestSuite '%s' started.\n",
      $suite->getName()
    );
  }
 
  public function
  endTestSuite(PHPUnit_Framework_TestSuite $suite)
  {
    printf(
      "TestSuite '%s' ended.\n",
      $suite->getName()
    );
  }
}
?>

显示如何运行和观测测试套件。

范例 23.4: 运行和观测测试套件


require_once 'PHPUnit/Framework.php';
 
require_once 'ArrayTest.php';
require_once 'SimpleTestListener.php';
 
// 创建一个包括测试套件,来自类ArrayTest的测试。
$suite = new PHPUnit_Framework_TestSuite('ArrayTest');
 
// 创建一个测试结果,并附上一个SimpleTestListener对象作为对它的观测者。
$result = new PHPUnit_Framework_TestResult;
$result->addListener(new SimpleTestListener);
 
// 运行测试。
$suite->run($result);
?>
TestSuite 'ArrayTest' started.
Test 'testNewArrayIsEmpty' started.
Test 'testNewArrayIsEmpty' ended.
Test 'testArrayContainsAnElement' started.
Test 'testArrayContainsAnElement' ended.
TestSuite 'ArrayTest' ended.

新测试运行器

如果你需要从测试运行得到不同的反馈,编写你自己的测试启动器,交互式的或非交互的。为类PHPUnit_TextUI_TestRunner(PHPUnit命令行测试启动器)所继承的抽象类PHPUnit_Runner_BaseTestRunner可作为起点。

阅读(1539) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~