TestCase

単純なテストでは、アサーションを次々と並べられます。とはいえ、アサーションをテストのクラスに包んで組み立てたほうがよいこともあります。

そのクラスは Tester\TestCase を継承しなければならず、私たちはそれを単に TestCase と呼びます。クラスには test で始まるテストのメソッドを入れます。それらのメソッドがテストとして実行されます。

use Tester\Assert;

class RectangleTest extends Tester\TestCase
{
	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# テストのメソッドを走らせます
(new RectangleTest)->run();

こうして書いた TestCase は、setUp()tearDown() のメソッドでさらに強められます。これらはそれぞれ、テストのメソッドの前と後に呼ばれます。

use Tester\Assert;

class NextTest extends Tester\TestCase
{
	protected function setUp()
	{
		# 準備
	}

	protected function tearDown()
	{
		# 後片付け
	}

	public function testOne()
	{
		Assert::same(/* ... */);
	}

	public function testTwo()
	{
		Assert::match(/* ... */);
	}
}

# テストのメソッドを走らせます
(new NextTest)->run();

/*


メソッドの呼ばれる順序
-----------------
setUp()
testOne()
tearDown()

setUp()
testTwo()
tearDown()
*/

setUp()tearDown() の段階でエラーが起きると、そのテストは全体として落ちます。テストのメソッドそのものでエラーが起きた場合も tearDown() メソッドは実行されますが、その中でのエラーは抑えられます。

テストのメソッドの中では、たとえば前提が満たされないときなど、いつでも $this->skip('理由') を呼んで今のテストを飛ばせます。

テストのファイルの先頭には @testCaseのアノテーションを書くことをおすすめします。そうするとコマンドラインのテストの実行器は、TestCase の個々のメソッドを別々のプロセスで、複数のスレッドを使って並行して実行します。おかげでテスト全体がかなり速くなります。

<?php
/** @testCase */

メソッドのアノテーション

テストのメソッドには、テストを楽にするアノテーションがいくつか使えます。テストのメソッドの上に書きます。

@throws

テストのメソッドの中で Assert::exception() を使うのと同じですが、書き方がすっきりします。

/**
 * @throws RuntimeException
 */
public function testOne()
{
	// ...
}


/**
 * @throws LogicException  Wrong argument order
 */
public function testTwo()
{
	// ...
}

@dataProvider

このアノテーションは、テストのメソッドを違うパラメータで何度も走らせたいときに役立ちます。(テストのファイルの同じ名前のアノテーションと混同しないでください。)

そのうしろに、テストのメソッドへの引数を返すメソッドの名前を書きます。そのメソッドは配列か Traversable のオブジェクトを返さなければなりません。単純な例です。

public function getLoopArgs()
{
	return [
		[1, 2, 3],
		[4, 5, 6],
		[7, 8, 9],
	];
}


/**
 * @dataProvider getLoopArgs
 */
public function testLoop($a, $b, $c)
{
	// ...
}

@dataProvider のアノテーションのもうひとつの書き方は、パラメータとして INI ファイルへのパス(テストのファイルからの相対)を受け取ります。メソッドは INI ファイルの区画の数だけ呼ばれます。loop-args.ini のファイルです。

[one]
a=1
b=2
c=3

[two]
a=4
b=5
c=6

[three]
a=7
b=8
c=9

そしてその INI ファイルを使うメソッドです。

/**
 * @dataProvider loop-args.ini
 */
public function testLoop($a, $b, $c)
{
	// ...
}

同じように、INI ファイルの代わりに PHP のスクリプトを指せます。それは配列か Traversable のオブジェクトを返さなければなりません。loop-args.php のファイルです。

return [
	['a' => 1, 'b' => 2, 'c' => 3],
	['a' => 4, 'b' => 5, 'c' => 6],
	['a' => 7, 'b' => 8, 'c' => 9],
];

テストのファイルのデータプロバイダと同じく、ファイル名のうしろに絞り込みの問い合わせを足せば、それに合う区画についてだけメソッドを走らせられます。