| Prev | Next |
テストを書きやすくする、あるいはテストの実行結果の表示方法を変更するなど、 PHPUnit はさまざまな方法で拡張することができます。 PHPUnit を拡張するための第一歩をここで説明します。
PHPUnit_Framework_TestCase を継承した抽象サブクラスにユーティリティメソッドを書き、 そのクラスをさらに継承してテストクラスを作成します。 これが、PHPUnit を拡張するための一番簡単な方法です。
PHPUnit_Extensions_TestDecorator のサブクラスでテストケースあるいはテストスイートをラッピングし、 デコレータパターンを使用することで 各テストの実行前後に何らかの処理をさせることができます。
PHPUnit には、PHPUnit_Extensions_RepeatedTest および PHPUnit_Extensions_TestSetup という 2 つの具象テストデコレータが付属しています。 前者はテストを繰り返し実行し、それらが全て成功した場合にのみ成功とみなします。 後者については 第 6 章 で説明しました。
例 22.1 は、テストデコレータ PHPUnit_Extensions_RepeatedTest の一部を抜粋したものです。独自のデコレータを作成するための参考にしてください。
例 22.1: RepeatedTest デコレータ
<?php
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 の実装より単純で、 これを用いて例えば データ駆動のテスト (data-driven tests) などを実行します。
カンマ区切り (CSV) ファイルの値と比較する、データ駆動のテストを 例 22.2 に示します。このファイルの各行は foo;bar のような形式になっており (訳注: CSV じゃない……)、 最初の値が期待値で 2 番目の値が実際の値です。
例 22.2: データ駆動のテスト
<?php
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 <bar> difference < x> got string <baz> /home/sb/DataDrivenTest.php:32 /home/sb/DataDrivenTest.php:53 FAILURES! Tests: 2, Failures: 1.
テスト結果をカスタマイズするために、必ず PHPUnit_Framework_TestResult のサブクラスを書かなければならないというわけではありません。たいていは、 新しい PHPUnit_Framework_TestListener を実装して (表 21.14 を参照ください)、 テストの前にそれを PHPUnit_Framework_TestResult オブジェクトにアタッチするだけで十分です。
例 22.3 は、PHPUnit_Framework_TestListener インターフェイスを実装する単純な例です。
例 22.3: シンプルなテストリスナー
<?php
require_once 'PHPUnit/Framework.php';
class SimpleTestListener
implements PHPUnit_Framework_TestListener
{
public function
addError(PHPUnit_Framework_Test $test,
Exception $e,
$time)
{
printf(
"テスト '%s' の実行中にエラーが発生しました。\n",
$test->getName()
);
}
public function
addFailure(PHPUnit_Framework_Test $test,
PHPUnit_Framework_AssertionFailedError $e,
$time)
{
printf(
"テスト '%s' に失敗しました。\n",
$test->getName()
);
}
public function
addIncompleteTest(PHPUnit_Framework_Test $test,
Exception $e,
$time)
{
printf(
"テスト '%s' は未完了です。\n",
$test->getName()
);
}
public function
addSkippedTest(PHPUnit_Framework_Test $test,
Exception $e,
$time)
{
printf(
"テスト '%s' は省略されました。\n",
$test->getName()
);
}
public function startTest(PHPUnit_Framework_Test $test)
{
printf(
"テスト '%s' が開始されました。\n",
$test->getName()
);
}
public function endTest(PHPUnit_Framework_Test $test, $time)
{
printf(
"テスト '%s' が終了しました。\n",
$test->getName()
);
}
public function
startTestSuite(PHPUnit_Framework_TestSuite $suite)
{
printf(
"テストスイート '%s' が開始されました。\n",
$suite->getName()
);
}
public function
endTestSuite(PHPUnit_Framework_TestSuite $suite)
{
printf(
"テストスイート '%s' が終了しました。\n",
$suite->getName()
);
}
}
?>
例 22.4 は、テストスイートを実行して監視する方法を示したものです。
例 22.4: テストスイートの実行と監視
<?php
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);
?>
テストスイート 'ArrayTest' が開始されました。 テスト 'testNewArrayIsEmpty' が開始されました。 テスト 'testNewArrayIsEmpty' が終了しました。 テスト 'testArrayContainsAnElement' が開始されました。 テスト 'testArrayContainsAnElement' が終了しました。 テストスイート 'ArrayTest' が終了しました。
| Prev | Next |
Copyright © 2005-2011 Sebastian Bergmann.