テストを書きやすくする、あるいはテストの実行結果の表示方法を変更するなど、 PHPUnit はさまざまな方法で拡張することができます。 PHPUnit を拡張するための第一歩をここで説明します。
PHPUnit2_Framework_TestCase
を継承した抽象サブクラスにユーティリティメソッドを書き、
そのクラスをさらに継承してテストクラスを作成します。
これが、PHPUnit を拡張するための一番簡単な方法です。
PHPUnit2_Extensions_TestDecorator
のサブクラスでテストケースあるいはテストスイートをラッピングし、
デコレータパターンを使用することで
各テストの実行前後に何らかの処理をさせることができます。
PHPUnit には、PHPUnit2_Extensions_RepeatedTest
および PHPUnit2_Extensions_TestSetup
という 2 つの具象テストデコレータが付属しています。
前者はテストを繰り返し実行し、それらが全て成功した場合にのみ成功とみなします。
後者については 5章Fixtures で説明しました。
例15.1「RepeatedTest デコレータ」
は、テストデコレータ PHPUnit2_Extensions_RepeatedTest
の一部を抜粋したものです。独自のデコレータを作成するための参考にしてください。
例15.1 RepeatedTest デコレータ
<?php
require_once 'PHPUnit2/Extensions/TestDecorator.php';
class PHPUnit2_Extensions_RepeatedTest extends PHPUnit2_Extensions_TestDecorator {
private $timesRepeat = 1;
public function __construct(PHPUnit2_Framework_Test $test, $timesRepeat = 1) {
parent::__construct($test);
if (is_integer($timesRepeat) &&
$timesRepeat >= 0) {
$this->timesRepeat = $timesRepeat;
}
}
public function countTestCases() {
return $this->timesRepeat * $this->test->countTestCases();
}
public function run($result = NULL) {
if ($result === NULL) {
$result = $this->createResult();
}
for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) {
$this->test->run($result);
}
return $result;
}
}
?>
PHPUnit2_Framework_Test インターフェイスの機能は限られており、
実装するのは簡単です。PHPUnit2_Framework_Test
を実装するのは PHPUnit2_Framework_TestCase の実装より単純で、
これを用いて例えば データ駆動のテスト (data-driven tests)
などを実行します。
カンマ区切り (CSV) ファイルの値と比較する、データ駆動のテストを
例15.2「データ駆動のテスト」
に示します。このファイルの各行は foo;bar
のような形式になっており (訳注: CSV じゃない……)、
最初の値が期待値で 2 番目の値が実際の値です。
例15.2 データ駆動のテスト
<?php
require_once 'PHPUnit2/Framework/Assert.php';
require_once 'PHPUnit2/Framework/Test.php';
require_once 'PHPUnit2/Framework/TestResult.php';
class DataDrivenTest implements PHPUnit2_Framework_Test {
private $lines;
public function __construct($dataFile) {
$this->lines = file($dataFile);
}
public function countTestCases() {
return sizeof($this->lines);
}
public function run($result = NULL) {
if ($result === NULL) {
$result = new PHPUnit2_Framework_TestResult;
}
$result->startTest($this);
foreach ($this->lines as $line) {
list($expected, $actual) = explode(';', $line);
try {
PHPUnit2_Framework_Assert::assertEquals(trim($expected), trim($actual));
}
catch (PHPUnit2_Framework_ComparisonFailure $e) {
$result->addFailure($this, $e);
}
catch (Exception $e) {
$result->addError($this, $e);
}
}
$result->endTest($this);
return $result;
}
}
$test = new DataDrivenTest('data_file.csv');
$result = $test->run();
$failures = $result->failures();
print $failures[0]->thrownException()->toString();
?>
expected: <foo> but was: <bar>
テスト結果をカスタマイズするために、必ず PHPUnit2_Framework_TestResult
のサブクラスを書かなければならないというわけではありません。たいていは、
新しい PHPUnit2_Framework_TestListener を実装して
(表14.10「TestListener のコールバック」 を参照ください)、
テストの前にそれを PHPUnit2_Framework_TestResult
オブジェクトにアタッチするだけで十分です。
例15.3「シンプルなテストリスナー」
は、PHPUnit2_Framework_TestListener
インターフェイスを実装する単純な例です。
例15.3 シンプルなテストリスナー
<?php
require_once 'PHPUnit2/Framework/TestListener.php';
class SimpleTestListener
implements PHPUnit2_Framework_TestListener {
public function
addError(PHPUnit2_Framework_Test $test, Exception $e) {
printf(
"テスト '%s' の実行中にエラーが発生しました。\n",
$test->getName()
);
}
public function
addFailure(PHPUnit2_Framework_Test $test,
PHPUnit2_Framework_AssertionFailedError $e) {
printf(
"テスト '%s' に失敗しました。\n",
$test->getName()
);
}
public function
addIncompleteTest(PHPUnit2_Framework_Test $test,
Exception $e) {
printf(
"テスト '%s' は未完了です。\n",
$test->getName()
);
}
public function startTest(PHPUnit2_Framework_Test $test) {
printf(
"テスト '%s' が開始されました。\n",
$test->getName()
);
}
public function endTest(PHPUnit2_Framework_Test $test) {
printf(
"テスト '%s' が終了しました。\n",
$test->getName()
);
}
public function
startTestSuite(PHPUnit2_Framework_TestSuite $suite) {
printf(
"テストスイート '%s' が開始されました。\n",
$suite->getName()
);
}
public function
endTestSuite(PHPUnit2_Framework_TestSuite $suite) {
printf(
"テストスイート '%s' が終了しました。\n",
$suite->getName()
);
}
}
?>
例15.4「テストスイートの実行と監視」 は、テストスイートを実行して監視する方法を示したものです。
例15.4 テストスイートの実行と監視
<?php
require_once 'PHPUnit2/Framework/TestResult.php';
require_once 'PHPUnit2/Framework/TestSuite.php';
require_once 'ArrayTest.php';
require_once 'SimpleTestListener.php';
// ArrayTest クラスのテストを含む
// テストスイートを作成します。
$suite = new PHPUnit2_Framework_TestSuite('ArrayTest');
// テスト結果オブジェクトを作成し、そこにオブザーバとして
// SimpleTestListener をアタッチします。
$result = new PHPUnit2_Framework_TestResult;
$result->addListener(new SimpleTestListener);
// テストを実行します。
$suite->run($result);
?>
テストスイート 'ArrayTest' が開始されました。 テスト 'testNewArrayIsEmpty' が開始されました。 テスト 'testNewArrayIsEmpty' が終了しました。 テスト 'testArrayContainsAnElement' が開始されました。 テスト 'testArrayContainsAnElement' が終了しました。 テストスイート 'ArrayTest' が終了しました。