Prev Next

第10章 テストダブル

Gerard Meszaros は、テストダブルの概念を [Meszaros2007] でこのように述べています。

 

Sometimes it is just plain hard to test the system under test (SUT) because it depends on other components that cannot be used in the test environment. This could be because they aren't available, they will not return the results needed for the test or because executing them would have undesirable side effects. In other cases, our test strategy requires us to have more control or visibility of the internal behavior of the SUT.

- テスト対象のシステム (SUT: system under test) をテストすることは、時に非常に困難なこととなります。というのも、 システムが他のコンポーネントに依存しており、 そのコンポーネントをテスト環境で利用できないことがあるからです。 そもそも使用不可能であったりテストで必要な結果を返さなかったり、 あるいは好ましくない副作用があったりといったことです。 それ以外の場合も、テスト環境の内部的な振る舞いをきちんと制御して 目に見えるようにしておくことが必要です。

When we are writing a test in which we cannot (or chose not to) use a real depended-on component (DOC), we can replace it with a Test Double. The Test Double doesn't have to behave exactly like the real DOC; it merely has to provide the same API as the real one so that the SUT thinks it is the real one!

- 実際に依存するコンポーネント (DOC: depended-on component) を使わないテストを書く場合は、それをテストダブルで置き換えることができます。 テストダブルは、必ずしも実際の DOC とまったく同様に動作する必要はありません。 単に実際のものと同じ API を提供し、 SUT に「これは本物だ!」と思わせるだけでいいのです。

 
  --Gerard Meszaros

PHPUnit の getMock($className) メソッドを使うと、 指定した元クラスのテストダブルとして振る舞うオブジェクトを自動的に生成することができます。 このテストダブルオブジェクトは、元クラスのオブジェクトを要するすべての場面で使うことができます。

デフォルトでは、元クラスのすべてのメソッドが置き換えられて、 (元のメソッドは呼び出さずに) 単に NULL を返すだけのダミー実装になります。たとえば will($this->returnValue()) メソッドを使うと、 ダミー実装がコールされたときに値を返すよう設定することができます。

制限

final, private および static メソッドのスタブやモックは作れないことに注意しましょう。 PHPUnit のテストダブル機能ではこれらを無視し、元のメソッドの振る舞いをそのまま維持します。

スタブ

実際のオブジェクトを置き換えて、 設定した何らかの値を (オプションで) 返すようなテストダブルのことを スタブ といいます。 スタブ を使うと、 「SUT が依存している実際のコンポーネントを置き換え、 SUT の入力を間接的にコントロールできるようにすることができます。 これにより、SUT が他の何者も実行しないことを強制させることができます。」

例 10.2 に、スタブメソッドの作成と返り値の設定の方法を示します。まず、 PHPUnit_Framework_TestCase クラスの getMock() メソッドを用いて SomeClass オブジェクトのスタブを作成します (例 10.1)。 次に、PHPUnit が提供する、いわゆる Fluent Interface (流れるようなインターフェイス) を用いてスタブの振る舞いを指定します。簡単に言うと、 いくつもの一時オブジェクトを作成して、 それらを連結するといった操作は必要ないということです。 そのかわりに、例にあるようにメソッドの呼び出しを連結します。 このほうが、より読みやすく "流れるような" コードとなります。

例 10.1: スタブを作りたいクラス

<?php
class SomeClass
{
public function doSomething()
{
// なにかをします
}
}
?>

例 10.2: メソッドに固定値を返させるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnValue('foo'));

// $stub->doSomething() をコールすると
// 'foo' を返すようになります
$this->assertEquals('foo', $stub->doSomething());
}
}
?>

舞台裏では、getMock() メソッドが使われたときに PHPUnit が自動的に、求める振る舞いを実装した新たな PHP のクラスを生成しています。 生成されるテストダブルクラスの設定は、 getMock() メソッドのオプションの引数を使って行います。

  • デフォルトでは、指定したクラスのすべてのメソッドが単に NULL を返すだけのテストダブルとなります。返り値を変更するには、たとえば will($this->returnValue()) を使います。

  • オプションの第二パラメータを指定すると、その配列の中に含まれる名前のメソッドだけがテストダブルに置き換えらて、その他のメソッドはそのままとなります。

  • オプションの第三パラメータには、元クラスのコンストラクタに渡すパラメータの配列を渡します (デフォルトでは、コンストラクタはダミー実装に置き換えられません)。

  • オプションの第四パラメータを使うと、生成されるテストダブルクラスのクラス名を指定することができます。

  • オプションの第五パラメータを使うと、元クラスのコンストラクタを呼び出さないようにすることができます。

  • オプションの第六パラメータを使うと、元クラスの clone コンストラクタを呼び出さないようにすることができます。

  • オプションの第七パラメータを使うと、テストダブルクラスの生成時に __autoload() を無効にすることができます。

もうひとつのやり方として、生成されたテストダブルクラスの設定を モックビルダー API で行うことができます。 例 10.3 に例を示します。 モックビルダーで使えるメソッドの一覧は次のとおりです。

  • setMethods(array $methods) をモックビルダーオブジェクト上でコールすると、テストダブルで置き換えるメソッドを指定することができます。その他のメソッドの挙動は変更しません。

  • setConstructorArgs(array $args) をコールしてパラメータの配列を渡すと、それを元クラスのコンストラクタに渡すことができます (デフォルトのダミー実装では、コンストラクタは置き換えません)。

  • setMockClassName($name) を使うと、生成されるテストダブルクラスのクラス名を指定することができます。

  • disableOriginalConstructor() を使うと、元クラスのコンストラクタを無効にすることができます。

  • disableOriginalClone() を使うと、元クラスのクローンコンストラクタを無効にすることができます。

  • disableAutoload() を使うと、テストダブルクラスを生成するときに __autoload() を無効にすることができます。

例 10.3: モックビルダー API を使った、生成されるテストダブルクラスの変更

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMockBuilder('SomeClass')
->disableOriginalConstructor()
->getMock();

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnValue('foo'));

// $stub->doSomething() をコールすると
// 'foo' を返すようになります
$this->assertEquals('foo', $stub->doSomething());
}
}
?>

時には、メソッドをコールした際の引数のひとつを (そのまま) スタブメソッドコールの返り値としたいこともあるでしょう。 例 10.4 は、 returnValue() のかわりに returnArgument() を用いてこれを実現する例です。

例 10.4: メソッドに引数のひとつを返させるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnArgumentStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnArgument(0));

// $stub->doSomething('foo') は 'foo' を返します
$this->assertEquals('foo', $stub->doSomething('foo'));

// $stub->doSomething('bar') は 'bar' を返します
$this->assertEquals('bar', $stub->doSomething('bar'));
}
}
?>

流れるようなインターフェイスをテストするときには、 スタブメソッドがオブジェクト自身への参照を返すようにできると便利です。 例 10.5 は、 returnSelf() を使ってこれを実現する例です。

例 10.5: スタブオブジェクトへの参照を返すメソッドのスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnSelf()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnSelf());

// $stub->doSomething() は $stub を返します
$this->assertSame($stub, $stub->doSomething());
}
}
?>

スタブメソッドをコールした結果として、 定義済みの引数リストにあわせて異なる値を返さなければならないこともあるでしょう。 returnValueMap() を使えば、 マップを作って引数と関連付け、それを返り値に対応させることができます。 例 10.6 を参照ください。

例 10.6: メソッドにマップからの値を返させるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnValueMapStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// 値を返すための、引数のマップを作製します
$map = array(
array('a', 'b', 'c', 'd'),
array('e', 'f', 'g', 'h')
);

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnValueMap($map));

// $stub->doSomething() は、渡した引数に応じて異なる値を返します
$this->assertEquals('d', $stub->doSomething('a', 'b', 'c'));
$this->assertEquals('h', $stub->doSomething('e', 'f', 'g'));
}
}
?>

スタブメソッドをコールした結果として固定値 (returnValue() を参照ください) や (不変の) 引数 (returnArgument() を参照ください) ではなく計算した値を返したい場合は、 returnCallback() を使用します。 これは、スタブメソッドからコールバック関数やメソッドの結果を返させます。 例 10.7 を参照ください。

例 10.7: メソッドにコールバックからの値を返させるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testReturnCallbackStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->returnCallback('str_rot13'));

// $stub->doSomething($argument) は str_rot13($argument) を返します
$this->assertEquals('fbzrguvat', $stub->doSomething('something'));
}
}
?>

コールバックメソッドを設定するよりももう少しシンプルな方法として、 希望する返り値のリストを指定することもできます。この場合に使うのは onConsecutiveCalls() メソッドです。 例 10.8 の例を参照ください。

例 10.8: メソッドに、リストで指定した値をその順で返させるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testOnConsecutiveCallsStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->onConsecutiveCalls(2, 3, 5, 7));

// $stub->doSomething() は毎回異なる値を返します
$this->assertEquals(2, $stub->doSomething());
$this->assertEquals(3, $stub->doSomething());
$this->assertEquals(5, $stub->doSomething());
}
}
?>

値を返すのではなく、スタブメソッドで例外を発生させることもできます。 例 10.9 に、throwException() でこれを行う方法を示します。

例 10.9: メソッドに例外をスローさせるスタブ

<?php
require_once 'SomeClass.php';

class StubTest extends PHPUnit_Framework_TestCase
{
public function testThrowExceptionStub()
{
// SomeClass クラスのスタブを作成します
$stub = $this->getMock('SomeClass');

// スタブの設定を行います
$stub->expects($this->any())
->method('doSomething')
->will($this->throwException(new Exception));

// $stub->doSomething() は例外をスローします
$stub->doSomething();
}
}
?>

また、スタブを使用することで、よりよい設計を行うことができるようにもなります。 あちこちで使用されているリソースを単一の窓口 (façade : ファサード) 経由でアクセスするようにすることで、 それを簡単にスタブに置き換えられるようになります。例えば、 データベースへのアクセスのコードをそこらじゅうにちりばめるのではなく、 その代わりに IDatabase インターフェイスを実装した単一の Database オブジェクトを使用するようにします。すると、 IDatabase を実装したスタブを作成することで、 それをテストに使用できるようになるのです。同時に、 テストを行う際にスタブデータベースを使用するか 本物のデータベースを使用するかを選択できるようになります。 つまり開発時にはローカル環境でテストし、 統合テスト時には実際のデータベースでテストするといったことができるようになるのです。

スタブ化しなければならない機能は、たいてい同一オブジェクト内で密結合しています。 この機能ををひとつの結合したインターフェイスにまとめることで、 システムのそれ以外の部分との結合を緩やかにすることができます。

モックオブジェクト

実際のオブジェクトを置き換えて、 (メソッドがコールされたことなどの) 期待する内容を検証するテストダブルのことを モック といいます。

モックオブジェクト は SUT の間接的な出力の内容を検証するために使用する観測地点です。 一般的に、モックオブジェクトにはテスト用スタブの機能も含まれます。 まだテストに失敗していない場合に、間接的な出力の検証用の値を SUT に返す機能です。 したがって、モックオブジェクトとは テスト用スタブにアサーション機能を足しただけのものとは異なります。 それ以外の用途にも使うことができます。

ひとつ例を示します。ここでは、別のオブジェクトを観察している あるオブジェクトの特定のメソッド (この例では update()) が正しくコールされたかどうかを調べるものとします。 例 10.10 は、テスト対象のシステム (SUT) の一部である Subject クラスと Observer クラスのコードです。

例 10.10: テスト対象のシステム (SUT) の一部である Subject クラスと Observer クラス

<?php
class Subject
{
protected $observers = array();

public function attach(Observer $observer)
{
$this->observers[] = $observer;
}

public function doSomething()
{
// なにかをします
// ...

// なにかしたということをオブザーバに通知します
$this->notify('something');
}

public function doSomethingBad()
{
foreach ($this->observers as $observer) {
$observer->reportError(42, 'Something bad happened', $this);
}
}

protected function notify($argument)
{
foreach ($this->observers as $observer) {
$observer->update($argument);
}
}

// その他のメソッド
}

class Observer
{
public function update($argument)
{
// なにかをします
}

public function reportError($errorCode, $errorMessage, Subject $subject)
{
// なにかをします
}

// その他のメソッド
}
?>

例 10.11 では、モックオブジェクトを作成して Subject オブジェクトと Observer オブジェクトの対話をテストする方法を説明します。

まず PHPUnit_Framework_TestCase クラスの getMock() メソッド を使用して Observer のモックオブジェクトを作成します。 getMock() メソッドの二番目の (オプションの) パラメータに配列を指定しているので、Observer クラスの中の update() メソッドについてのみモック実装が作成されます。

例 10.11: あるメソッドが、指定した引数で一度だけコールされることを確かめるテスト

<?php
class SubjectTest extends PHPUnit_Framework_TestCase
{
public function testObserversAreUpdated()
{
// Observer クラスのモックを作成します。
// update() メソッドのみのモックです。
$observer = $this->getMock('Observer', array('update'));

// update() メソッドが一度だけコールされ、その際の
// パラメータは文字列 'something' となる、
// ということを期待しています。
$observer->expects($this->once())
->method('update')
->with($this->equalTo('something'));

// Subject オブジェクトを作成し、Observer オブジェクトの
// モックをアタッチします。
$subject = new Subject;
$subject->attach($observer);

// $subject オブジェクトの doSomething() メソッドをコールします。
// これは、Observer オブジェクトのモックの update() メソッドを、
// 文字列 'something' を引数としてコールすることを期待されています。
$subject->doSomething();
}
}
?>

with() メソッドには任意の数の引数を渡すことができます。 これは、モック対象のメソッドのパラメータ数に対応します。 メソッドの引数に対して、単なるマッチだけでなくより高度な制約を指定することもできます。

例 10.12: メソッドが引数つきでコールされることを、さまざまな制約の下でテストする例

<?php
class SubjectTest extends PHPUnit_Framework_TestCase
{
public function testErrorReported()
{
// Observer クラスのモックを作成します。
// reportError() メソッドをモックします。
$observer = $this->getMock('Observer', array('reportError'));

$observer->expects($this->once())
->method('reportError')
->with($this->greaterThan(0),
$this->stringContains('Something'),
$this->anything());

$subject = new Subject;
$subject->attach($observer);

// doSomethingBad() メソッドは、
// reportError() メソッドを通じてオブザーバにエラーを報告しなければなりません。
$subject->doSomethingBad();
}
}
?>

表 4.3 はメソッドの引数に適用できる制約、そして 表 10.1 は起動回数を指定するために使える matcher です。

表10.1 Matchers

Matcher 意味
PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount any() 評価対象のメソッドがゼロ回以上実行された際にマッチするオブジェクトを返します。
PHPUnit_Framework_MockObject_Matcher_InvokedCount never() 評価対象のメソッドが実行されなかった際にマッチするオブジェクトを返します。
PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce atLeastOnce() 評価対象のメソッドが最低一回以上実行された際にマッチするオブジェクトを返します。
PHPUnit_Framework_MockObject_Matcher_InvokedCount once() 評価対象のメソッドが一度だけ実行された際にマッチするオブジェクトを返します。
PHPUnit_Framework_MockObject_Matcher_InvokedCount exactly(int $count) 評価対象のメソッドが指定した回数だけ実行された際にマッチするオブジェクトを返します。
PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex at(int $index) 評価対象のメソッドが $index 回目に実行された際にマッチするオブジェクトを返します。

getMockForAbstractClass() メソッドは、 抽象クラスのモックオブジェクトを返します。 そのクラスのすべての抽象メソッドがモックの対象となります。 これを使えば、抽象クラスにある具象メソッドをテストすることができます。

例 10.13: 抽象クラスの具象メソッドのテスト

<?php
abstract class AbstractClass
{
public function concreteMethod()
{
return $this->abstractMethod();
}

public abstract function abstractMethod();
}

class AbstractClassTest extends PHPUnit_Framework_TestCase
{
public function testConcreteMethod()
{
$stub = $this->getMockForAbstractClass('AbstractClass');
$stub->expects($this->any())
->method('abstractMethod')
->will($this->returnValue(TRUE));

$this->assertTrue($stub->concreteMethod());
}
}
?>

ウェブサービスのスタブおよびモック

ウェブサービスとのやりとりを行うアプリケーションを、 実際にウェブサービスとやりとりすることなくテストしたくなることもあるでしょう。 ウェブサービスのスタブやモックを作りやすくするために getMockFromWsdl() メソッドが用意されており、これは getMock() (上を参照ください) とほぼ同様に使うことができます。唯一の違いは、 getMockFromWsdl() が返すスタブやモックが WSDL のウェブサービス記述にもとづくものであるのに対して getMock() が返すスタブやモックが PHP のクラスやインターフェイスにもとづくものであるという点です。

例 10.14 は、getMockFromWsdl() を使って GoogleSearch.wsdl に記述されたウェブサービスのスタブを作る例です。

例 10.14: ウェブサービスのスタブ

<?php
class GoogleTest extends PHPUnit_Framework_TestCase
{
public function testSearch()
{
$googleSearch = $this->getMockFromWsdl(
'GoogleSearch.wsdl', 'GoogleSearch'
);

$directoryCategory = new StdClass;
$directoryCategory->fullViewableName = '';
$directoryCategory->specialEncoding = '';

$element = new StdClass;
$element->summary = '';
$element->URL = 'http://www.phpunit.de/';
$element->snippet = '...';
$element->title = '<b>PHPUnit</b>';
$element->cachedSize = '11k';
$element->relatedInformationPresent = TRUE;
$element->hostName = 'www.phpunit.de';
$element->directoryCategory = $directoryCategory;
$element->directoryTitle = '';

$result = new StdClass;
$result->documentFiltering = FALSE;
$result->searchComments = '';
$result->estimatedTotalResultsCount = 378000;
$result->estimateIsExact = FALSE;
$result->resultElements = array($element);
$result->searchQuery = 'PHPUnit';
$result->startIndex = 1;
$result->endIndex = 1;
$result->searchTips = '';
$result->directoryCategories = array();
$result->searchTime = 0.248822;

$googleSearch->expects($this->any())
->method('doGoogleSearch')
->will($this->returnValue($result));

/**
* $googleSearch->doGoogleSearch() はスタブが用意した結果を返し、
* ウェブサービスの doGoogleSearch() が呼び出されることはありません
*/
$this->assertEquals(
$result,
$googleSearch->doGoogleSearch(
'00000000000000000000000000000000',
'PHPUnit',
0,
1,
FALSE,
'',
FALSE,
'',
'',
''
)
);
}
}
?>

ファイルシステムのモック

vfsStream仮想ファイルシステム 用の ストリームラッパー で、 ユニットテストにおいて実際のファイルシステムのモックを作るときに有用です。

vfsStream をインストールするには、配布元の PEAR チャンネル (pear.php-tools.net) をローカルの PEAR 環境に登録しなければなりません。

pear channel-discover pear.php-tools.net

これが必要なのは最初の一度だけです。これで、 PEAR インストーラを使って vfsStream をインストールできるようになりました。

pear install pat/vfsStream-beta

例 10.15 は、ファイルシステムを操作するクラスの例です。

例 10.15: ファイルシステムを操作するクラス

<?php
class Example
{
protected $id;
protected $directory;

public function __construct($id)
{
$this->id = $id;
}

public function setDirectory($directory)
{
$this->directory = $directory . DIRECTORY_SEPARATOR . $this->id;

if (!file_exists($this->directory)) {
mkdir($this->directory, 0700, TRUE);
}
}
}?>

vfsStream のような仮想ファイルシステムがなければ、外部への影響なしに setDirectory() メソッドを個別にテストすることができません (例 10.16 を参照ください)。

例 10.16: ファイルシステムを操作するクラスのテスト

<?php
require_once 'Example.php';

class ExampleTest extends PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (file_exists(dirname(__FILE__) . '/id')) {
rmdir(dirname(__FILE__) . '/id');
}
}

public function testDirectoryIsCreated()
{
$example = new Example('id');
$this->assertFalse(file_exists(dirname(__FILE__) . '/id'));

$example->setDirectory(dirname(__FILE__));
$this->assertTrue(file_exists(dirname(__FILE__) . '/id'));
}

protected function tearDown()
{
if (file_exists(dirname(__FILE__) . '/id')) {
rmdir(dirname(__FILE__) . '/id');
}
}
}
?>

この方式には、次のような問題があります。

  • 外部のリソースを使うため、ファイルシステムのテストが断続的になる可能性があります。その結果、テストがあまり当てにならないものになります。

  • setUp()tearDown() で、テストの前後にそのディレクトリがないことを確認する必要があります。

  • tearDown() メソッドを実行する前にテストが異常終了したときに、ファイルシステム上にディレクトリが残ったままとなります。

例 10.17 は、vfsStream を使ってファイルシステムのモックを作成し、 ファイルシステムを操作するクラスのテストを行う例です。

例 10.17: ファイルシステムを操作するクラスのテストにおけるファイルシステムのモックの作成

<?php
require_once 'vfsStream/vfsStream.php';
require_once 'Example.php';

class ExampleTest extends PHPUnit_Framework_TestCase
{
public function setUp()
{
vfsStreamWrapper::register();
vfsStreamWrapper::setRoot(new vfsStreamDirectory('exampleDir'));
}

public function testDirectoryIsCreated()
{
$example = new Example('id');
$this->assertFalse(vfsStreamWrapper::getRoot()->hasChild('id'));

$example->setDirectory(vfsStream::url('exampleDir'));
$this->assertTrue(vfsStreamWrapper::getRoot()->hasChild('id'));
}
}
?>

この方式には次のような利点があります。

  • テストが簡潔になります。

  • vfsStream が、テスト対象のコードから操作するファイルシステム環境を用意してくれるので、開発者はそれを自由に扱えるようになります。

  • 実際のファイルシステムを操作することがなくなるので、tearDown() メソッドでの後始末が不要になります。

Prev Next
1. 自動テスト
2. PHPUnit の目標
3. PHPUnit のインストール
4. PHPUnit 用のテストの書き方
テストの依存性
データプロバイダ
例外のテスト
PHP のエラーのテスト
出力内容のテスト
アサーション
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertCount()
assertEmpty()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertInstanceOf()
assertInternalType()
assertLessThan()
assertLessThanOrEqual()
assertNull()
assertObjectHasAttribute()
assertRegExp()
assertStringMatchesFormat()
assertStringMatchesFormatFile()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
5. コマンドラインのテストランナー
Command-Line switches
6. Fixtures
tearDown() よりも setUp()
バリエーション
Fixture の共有
グローバルな状態
7. テストの構成
ファイルシステムを用いたテストスイートの構成
XML 設定ファイルを用いたテストスイートの構成
8. データベースのテスト
データベースのテストに対応しているベンダー
データベースのテストの難しさ
データベーステストの四段階
1. データベースのクリーンアップ
2. フィクスチャの準備
3–5. テストの実行、結果の検証、そして後始末
PHPUnit のデータベーステストケースの設定
getConnection() の実装
getDataSet() の実装
データベーススキーマ (DDL) とは?
ヒント: 自前でのデータベーステストケースの抽象化
データセットとデータテーブルについて知る
利用できる実装
外部キーには注意
自作のデータセットやデータテーブルの実装
接続 API
データベースアサーション API
テーブルの行数のアサーション
テーブルの状態のアサーション
クエリの結果のアサーション
複数のテーブルの状態のアサーション
よくある質問
PHPUnit は、テストごとにデータベーススキーマを作り直すの?
PDO を使ったアプリケーションじゃないと Database Extension を使えないの?
Too much Connections というエラーが出たらどうすればいい?
フラット XML や CSV のデータセットで NULL を扱う方法は?
9. 不完全なテスト・テストの省略
不完全なテスト
テストの省略
10. テストダブル
スタブ
モックオブジェクト
ウェブサービスのスタブおよびモック
ファイルシステムのモック
11. テストの進め方
開発中のテスト
デバッグ中のテスト
12. テスト駆動開発
銀行口座の例
13. 振舞駆動開発
ボウリングゲームの例
14. コードカバレッジ解析
カバーするメソッドの指定
コードブロックの無視
ファイルのインクルードや除外
エッジケース
15. テストのその他の使用法
アジャイルな文書作成
複数チームでのテスト
16. 雛形ジェネレータ
テストケースクラスの雛形の作成
テストケースクラスからのクラスの雛形の作成
17. PHPUnit と Selenium
Selenium Server
インストール
PHPUnit_Extensions_Selenium2TestCase
PHPUnit_Extensions_SeleniumTestCase
18. ログ出力
テスト結果 (XML)
テスト結果 (TAP)
テスト結果 (JSON)
コードカバレッジ (XML)
コードカバレッジ (テキスト)
19. PHPUnit の拡張
PHPUnit_Framework_TestCase のサブクラスの作成
カスタムアサーションの作成
PHPUnit_Framework_TestListener の実装
PHPUnit_Extensions_TestDecorator のサブクラスの作成
PHPUnit_Framework_Test の実装
A. アサーション
B. アノテーション
@assert
@author
@backupGlobals
@backupStaticAttributes
@codeCoverageIgnore*
@covers
@dataProvider
@depends
@expectedException
@expectedExceptionCode
@expectedExceptionMessage
@group
@outputBuffering
@runTestsInSeparateProcesses
@runInSeparateProcess
@test
@testdox
@ticket
C. XML 設定ファイル
PHPUnit
テストスイート
グループ
コードカバレッジ対象のファイルの追加や除外
ログ出力
テストリスナー
PHP INI 項目や定数、グローバル変数の設定
Selenium RC の設定ブラウザ
D. 目次
E. 参考文献
F. 著作権