| Prev | Next |
例 4.1 で、 PHP の配列操作のテストを PHPUnit 用に書く方法を示します。 この例では、PHPUnit を使ったテストを書く際の基本的な決まり事や手順を紹介します。
Class という名前のクラスのテストは、ClassTest という名前のクラスに記述します。
ClassTest は、(ほとんどの場合) PHPUnit_Framework_TestCase を継承します。
テストは、test* という名前のパブリックメソッドとなります。
あるいは、@test アノテーションをメソッドのコメント部で使用することで、それがテストメソッドであることを示すこともできます。
テストメソッドの中で assertEquals() のようなアサーションメソッド (「PHPUnit_Framework_Assert」 を参照ください) を使用して、期待される値と実際の値が等しいことを確かめます。
例 4.1: PHPUnit での配列操作のテスト
<?php
require_once 'PHPUnit/Framework.php';
class StackTest extends PHPUnit_Framework_TestCase
{
public function testPushAndPop()
{
$stack = array();
$this->assertEquals(0, count($stack));
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertEquals(1, count($stack));
$this->assertEquals('foo', array_pop($stack));
$this->assertEquals(0, count($stack));
}
}
?>
|
Whenever you are tempted to type something into a
何かを |
||
| --Martin Fowler | ||
|
Unit Tests are primarily written as a good practice to help developers identify and fix bugs, to refactor code and to serve as documentation for a unit of software under test. To achieve these benefits, unit tests ideally should cover all the possible paths in a program. One unit test usually covers one specific path in one function or method. However a test method is not necessary an encapsulated, independent entity. Often there are implicit dependencies between test methods, hidden in the implementation scenario of a test. ユニットテストを書くそもそもの目的は、バグを発見と修正や コードのリファクタリングを開発者がやりやすくすること。 そしてテスト対象のソフトウェアのドキュメントとしての役割を果たすことだ。 これらの目的を達成するためには、 ユニットテストがプログラム内のすべてのルートをカバーしていることが理想である。 ひとつのユニットテストがカバーするのは、 通常はひとつの関数やメソッド内の特定のルートだけとなる。 しかし、テストメソッドは必ずしもカプセル化して独立させる必要はない。 複数のテストメソッドの間に暗黙の依存性があって、 隠された実装シナリオがテストの中にあるのもよくあることだ。 |
||
| --Adrian Kuhn et. al. | ||
PHPUnit は、テストメソッド間の依存性の明示的な宣言をサポートしています。 この依存性とは、テストメソッドが実行される順序を定義するものではありません。 プロデューサーがテストフィクスチャを作ってそのインスタンスを返し、 依存するコンシューマーがそれを受け取って利用するというものです。
プロデューサーとは、返り値としてテスト対象のユニットを生成するテストメソッドのこと。
コンシューマーとは、プロデューサーの返り値に依存するテストメソッドのこと。
例 4.2 は、@depends アノテーションを使ってテストメソッドの依存性をあらわす例です。
例 4.2: @depends アノテーションを使った依存性の表現
<?php
class StackTest extends PHPUnit_Framework_TestCase
{
public function testEmpty()
{
$stack = array();
$this->assertTrue(empty($stack));
return $stack;
}
/**
* @depends testEmpty
*/
public function testPush(array $stack)
{
array_push($stack, 'foo');
$this->assertEquals('foo', $stack[count($stack)-1]);
$this->assertFalse(empty($stack));
return $stack;
}
/**
* @depends testPush
*/
public function testPop(array $stack)
{
$this->assertEquals('foo', array_pop($stack));
$this->assertTrue(empty($stack));
}
}
?>
上の例では、まず最初のテスト testEmpty() で新しい配列を作り、それが空であることを確かめます。 このテストは、フィクスチャを返します。 二番目のテスト testPush() は testEmpty() に依存しており、 依存するテストの結果を引数として受け取ります。 最後の testPop() は testPush() に依存しています。
問題の局所化を手早く行うには、失敗したテストに目を向けやすくしたいものです。 そのため PHPUnit では、 あるテストが失敗したときにはそのテストに依存する他のテストの実行をスキップします。 テスト間の依存性を活用して問題点を見つけやすくしている例を 例 4.3 に示します。
例 4.3: テストの依存性の活用
<?php
class DependencyFailureTest extends PHPUnit_Framework_TestCase
{
public function testOne()
{
$this->assertTrue(FALSE);
}
/**
* @depends testOne
*/
public function testTwo()
{
}
}
?>
phpunit --verbose DependencyFailureTest
PHPUnit 3.4.14 by Sebastian Bergmann.
DependencyFailureTest
FS
Time: 0 seconds
There was 1 failure:
1) testOne(DependencyFailureTest)
Failed asserting that <boolean:false> is true.
/home/sb/DependencyFailureTest.php:6
There was 1 skipped test:
1) testTwo(DependencyFailureTest)
This test depends on "DependencyFailureTest::testOne" to pass.
FAILURES!
Tests: 2, Assertions: 1, Failures: 1, Skipped: 1.
ひとつのテストに複数の @depends アノテーションをつけることもできます。 PHPUnit はテストが実行される順序を変更しないので、 テストが実行されるときに確実に依存性が満たされているようにしておく必要があります。
テストメソッドには任意の引数を渡すことができます。 この引数は、データプロバイダメソッド (例 4.4 の provider()) で指定します。使用するデータプロバイダメソッドを指定するには @dataProvider アノテーションを使用します。
データプロバイダメソッドは、public でなければなりません。また、 メソッドの返り値の型は、配列の配列あるいはオブジェクト (Iterator インターフェイスを実装しており、 反復処理の際に配列を返すもの) である必要があります。 この返り値の各要素に対して、その配列の中身を引数としてテストメソッドがコールされます。
例 4.4: データプロバイダの使用
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
/**
* @dataProvider provider
*/
public function testAdd($a, $b, $c)
{
$this->assertEquals($c, $a + $b);
}
public function provider()
{
return array(
array(0, 0, 0),
array(0, 1, 1),
array(1, 0, 1),
array(1, 1, 3)
);
}
}
?>
phpunit DataTest
PHPUnit 3.4.14 by Sebastian Bergmann.
...F
Time: 0 seconds
There was 1 failure:
1) testAdd(DataTest) with data (1, 1, 3)
Failed asserting that <integer:2> matches expected value <integer:3>.
/home/sb/DataTest.php:21
FAILURES!
Tests: 4, Assertions: 4, Failures: 1.
例 4.5 は、テストするコード内で例外がスローされたかどうかを @expectedException アノテーションを使用して調べる方法を示すものです。
例 4.5: @expectedException アノテーションの使用法
<?php
require_once 'PHPUnit/Framework.php';
class ExceptionTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException InvalidArgumentException
*/
public function testException()
{
}
}
?>
phpunit ExceptionTest
PHPUnit 3.4.14 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) testException(ExceptionTest)
Expected exception InvalidArgumentException
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
一方、setExpectedException() メソッドを使用して、発生するであろう例外を指定することもできます。この方法を 例 4.6 に示します。
例 4.6: テスト対象のコードで発生するであろう例外の指定
<?php
require_once 'PHPUnit/Framework.php';
class ExceptionTest extends PHPUnit_Framework_TestCase
{
public function testException()
{
$this->setExpectedException('InvalidArgumentException');
}
}
?>
phpunit ExceptionTest
PHPUnit 3.4.14 by Sebastian Bergmann.
F
Time: 0 seconds
There was 1 failure:
1) testException(ExceptionTest)
Expected exception InvalidArgumentException
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
表 4.1 は、例外をテストするために用意されているメソッドをまとめたものです。
表4.1 例外のテスト用のメソッド
| メソッド | 意味 |
|---|---|
void setExpectedException(string $exceptionName)
|
発生することを期待する例外の名前を $exceptionName に設定します。
|
String getExpectedException()
|
発生することを期待する例外の名前を返します。 |
一方、 例 4.7 のような方法で例外をテストすることもできます。
例 4.7: 例外をテストするための、別の方法
<?php
require_once 'PHPUnit/Framework.php';
class ExceptionTest extends PHPUnit_Framework_TestCase {
public function testException() {
try {
// ... 例外が発生するであろうコード ...
}
catch (InvalidArgumentException $expected) {
return;
}
$this->fail('期待通りの例外が発生しませんでした。');
}
}
?>
例外が発生するはずの 例 4.7 のコードで例外が発生しなかった場合、それに続く fail() (表 22.2 を参照ください) によってテストが終了し、問題を報告します。期待通りに例外が発生すると、 catch ブロックが実行されてテストは正常終了します。
デフォルトでは、PHPUnit はテストの実行中に発生した PHP のエラーや警告そして notice を例外に変換します。これらの例外を用いて、たとえば 例 4.8 のように PHP のエラーが発生することをテストできます。
例 4.8: @expectedException を用いた、PHP エラーが発生することのテスト
<?php
class ExpectedErrorTest extends PHPUnit_Framework_TestCase
{
/**
* @expectedException PHPUnit_Framework_Error
*/
public function testFailingInclude()
{
include 'not_existing_file.php';
}
}
?>
phpunit ExpectedErrorTest
PHPUnit 3.4.14 by Sebastian Bergmann.
.
Time: 0 seconds
OK (1 test, 1 assertion)
PHPUnit_Framework_Error_Notice および PHPUnit_Framework_Error_Warning は、 それぞれ PHP の notice と警告に対応します。
| Prev | Next |
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertLessThan()
assertLessThanOrEqual()
assertNull()
assertObjectHasAttribute()
assertRegExp()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertType()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
Copyright © 2005-2011 Sebastian Bergmann.