迷惘的码农。
分类:
2008-04-08 11:37:15
PHPUnit能以各种不同的方式扩展,以使编写测试更容易并且定制来自运行测试的反馈。这是扩展PHPUnit的共同起点。
在抽象子类PHPUnit_Framework_TestCase
中编写工具方法并从该类得到你的测试用例类。这是扩展PHPUnit的最简单的方法之一。
编写你自己的类,它们带有专用于你的目的的断言。
你可以在PHPUnit_Extensions_TestDecorator
的子类中中封装测试用例或测试套件,并使用装饰者(Decorator)模式在测试运行前后执行某些动作。
PHPUnit自带两个具体的测试装饰者:PHPUnit_Extensions_RepeatedTest
和PHPUnit_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_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.
通过向run()
方法传入一个特殊用途的PHPUnit_Framework_TestResult
对象,你能改变测试运行的方式和收集的结果数据。
要定制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
可作为起点。