アノテーションとはメタデータを表す特別な構文のことで、
プログラミング言語のソースコードに追加することができます。
PHP そのものにはソースコードにアノテーションする専用の仕組みはありませんが、
ドキュメンテーションブロックに @アノテーション名 引数
のようなタグを書くことでアノテーションを表すという記法が
PHP コミュニティ内で一般に使われています。
PHP では、リフレクション API の getDocComment()
メソッドを使えば関数、クラス、メソッド、属性
それぞれのドキュメンテーションブロックにアクセスすることができます。
PHPUnit などのアプリケーションでは、
この情報をもとに実行時の振る舞いを設定するのです。
本章では、PHPUnit がサポートするすべてのアノテーションについて解説します。
@author
アノテーションは
@group
アノテーション (「@group」 を参照ください) のエイリアスで、
テストの作者にもとづいたフィルタリングができるようになります。
@after
アノテーションを使うと、
テストケースクラス内の各テストメソッドを実行した後に呼ぶメソッドを指定できます。
class MyTest extends PHPUnit_Framework_TestCase { /** * @after */ public function tearDownSomeFixtures() { // ... } /** * @after */ public function tearDownSomeOtherFixtures() { // ... } }
@afterClass
アノテーションを使うと、
テストケースクラス内の各テストメソッドを実行した後に呼ぶ静的メソッドを指定できます。
ここで共有フィクスチャの後始末をします。
class MyTest extends PHPUnit_Framework_TestCase { /** * @afterClass */ public static function tearDownSomeSharedFixtures() { // ... } /** * @afterClass */ public static function tearDownSomeOtherSharedFixtures() { // ... } }
グローバル変数の保存や復元を、テストケースクラスのすべてのテストで完全に無効にすることができます。 このように使います。
/** * @backupGlobals disabled */ class MyTest extends PHPUnit_Framework_TestCase { // ... }
@backupGlobals
アノテーションは、テストメソッドレベルで使うこともできます。
これによって、保存と復元の操作をより細やかに制御できるようになります。
/** * @backupGlobals disabled */ class MyTest extends PHPUnit_Framework_TestCase { /** * @backupGlobals enabled */ public function testThatInteractsWithGlobalVariables() { // ... } }
クラスの静的属性の保存や復元を、テストケースクラスのすべてのテストで完全に無効にすることができます。 このように使います。
/** * @backupStaticAttributes disabled */ class MyTest extends PHPUnit_Framework_TestCase { // ... }
@backupStaticAttributes
アノテーションは、テストメソッドレベルで使うこともできます。
これによって、保存と復元の操作をより細やかに制御できるようになります。
/** * @backupStaticAttributes disabled */ class MyTest extends PHPUnit_Framework_TestCase { /** * @backupStaticAttributes enabled */ public function testThatInteractsWithStaticAttributes() { // ... } }
@before
アノテーションを使うと、
テストケースクラス内の各テストメソッドを実行する前に呼ぶメソッドを指定できます。
class MyTest extends PHPUnit_Framework_TestCase { /** * @before */ public function setupSomeFixtures() { // ... } /** * @before */ public function setupSomeOtherFixtures() { // ... } }
@beforeClass
アノテーションを使うと、
テストケースクラス内の各テストメソッドを実行する前に呼ぶ静的メソッドを指定できます。
ここで共有フィクスチャの準備をします。
class MyTest extends PHPUnit_Framework_TestCase { /** * @beforeClass */ public static function setUpSomeSharedFixtures() { // ... } /** * @beforeClass */ public static function setUpSomeOtherSharedFixtures() { // ... } }
@codeCoverageIgnore
や
@codeCoverageIgnoreStart
、そして
@codeCoverageIgnoreEnd
アノテーションを使うと、
コード内の特定の行をカバレッジ解析の対象外にできます。
利用法は 「コードブロックの無視」 を参照ください。
@covers
アノテーションをテストコードで使うと、
そのテストメソッドがどのメソッドをテストするのかを指定することができます。
/** * @covers BankAccount::getBalance */ public function testBalanceIsInitiallyZero() { $this->assertEquals(0, $this->ba->getBalance()); }
これを指定した場合は、指定したメソッドのみのコードカバレッジ情報を考慮することになります。
表 B.1
に @covers
アノテーションの構文を示します。
表B.1 カバーするメソッドを指定するためのアノテーション
アノテーション | 説明 |
---|---|
@covers ClassName::methodName | そのテストメソッドが指定したメソッドをカバーすることを表します。 |
@covers ClassName | そのテストメソッドが指定したクラスのすべてのメソッドをカバーすることを表します。 |
@covers ClassName<extended> | そのテストメソッドが、指定したクラスとその親クラスおよびインターフェイスのすべてのメソッドをカバーすることを表します。 |
@covers ClassName::<public> | そのテストメソッドが、指定したクラスのすべての public メソッドをカバーすることを表します。 |
@covers ClassName::<protected> | そのテストメソッドが、指定したクラスのすべての protected メソッドをカバーすることを表します。 |
@covers ClassName::<private> | そのテストメソッドが、指定したクラスのすべての private メソッドをカバーすることを表します。 |
@covers ClassName::<!public> | そのテストメソッドが、指定したクラスのすべての非 public メソッドをカバーすることを表します。 |
@covers ClassName::<!protected> | そのテストメソッドが、指定したクラスのすべての非 protected メソッドをカバーすることを表します。 |
@covers ClassName::<!private> | そのテストメソッドが、指定したクラスのすべての非 private メソッドをカバーすることを表します。 |
@covers ::functionName | そのテストメソッドが、指定したグローバル関数をカバーすることを表します。 |
@coversDefaultClass
アノテーションを使うと、
デフォルトの名前空間あるいはクラス名を指定できます。
こうすることで、
@covers
アノテーションのたびに長い名前を繰り返す必要がなくなります。
例 B.1
を参照ください。
例 B.1: @coversDefaultClass を使ったアノテーションの短縮
<?php /** * @coversDefaultClass \Foo\CoveredClass */ class CoversDefaultClassTest extends PHPUnit_Framework_TestCase { /** * @covers ::publicMethod */ public function testSomething() { $o = new Foo\CoveredClass; $o->publicMethod(); } } ?>
@coversNothing
アノテーションをテストコードで使うと、
そのテストケースについてはコードカバレッジ情報を記録しないように指定できます。
これはインテグレーションテストで使えます。例として 例 11.3 を参照ください。
このメソッドはクラスレベルおよびメソッドレベルで使え、
あらゆる @covers
タグを上書きします。
テストメソッドには任意の引数を渡すことができます。
引数は、データプロバイダメソッド
(例 2.5 の
provider()
) から渡されます。
使用するデータプロバイダメソッドを指定するには
@dataProvider
アノテーションを使います。
詳細は 「データプロバイダ」 を参照ください。
PHPUnit は、テストメソッド間の依存性の明示的な宣言をサポートしています。
この依存性とは、テストメソッドが実行される順序を定義するものではありません。
プロデューサーがテストフィクスチャを作ってそのインスタンスを返し、
依存するコンシューマーがそれを受け取って利用するというものです。
例 2.2
は、@depends
アノテーションを使ってテストメソッドの依存性をあらわす例です。
詳細は 「テストの依存性」 を参照ください。
@expectedExceptionCode
アノテーションを
@expectedException
と組み合わせて使うと、
スローされた例外のエラーコードについてのアサーションが可能となり、
例外をより狭い範囲に特定できるようになります。
class MyTest extends PHPUnit_Framework_TestCase { /** * @expectedException MyException * @expectedExceptionCode 20 */ public function testExceptionHasErrorcode20() { throw new MyException('Some Message', 20); } }
テストを実行しやすくし、重複を減らすために、
ショートカットを使ってクラス定数を指定することができます。
@expectedExceptionCode
で
"@expectedExceptionCode ClassName::CONST
" のようにして使います。
class MyTest extends PHPUnit_Framework_TestCase { /** * @expectedException MyException * @expectedExceptionCode MyClass::ERRORCODE */ public function testExceptionHasErrorcode20() { throw new MyException('Some Message', 20); } } class MyClass { const ERRORCODE = 20; }
@expectedExceptionMessage
アノテーションは
@expectedExceptionCode
と似ており、
例外のエラーメッセージに関するアサーションを行います。
class MyTest extends PHPUnit_Framework_TestCase { /** * @expectedException MyException * @expectedExceptionMessage Some Message */ public function testExceptionHasRightMessage() { throw new MyException('Some Message', 20); } }
期待するメッセージを、例外メッセージの一部にすることもできます。 これは、特定の名前や渡したパラメータが例外に表示されることを確かめたいけれども 例外メッセージ全体は固定していない場合に便利です。
class MyTest extends PHPUnit_Framework_TestCase { /** * @expectedException MyException * @expectedExceptionMessage broken */ public function testExceptionHasRightMessage() { $param = "broken"; throw new MyException('Invalid parameter "'.$param.'".', 20); } }
テストを実行しやすくし、重複を減らすために、
ショートカットを使ってクラス定数を指定することができます。
@expectedExceptionMessage
で
"@expectedExceptionMessage ClassName::CONST
" のようにして使います。
サンプルコードは 「@expectedExceptionCode」 を参照ください。
あるテストを、ひとつあるいは複数のグループに属するものとすることができます。
@group
アノテーションをこのように使用します。
class MyTest extends PHPUnit_Framework_TestCase { /** * @group specification */ public function testSomething() { } /** * @group regresssion * @group bug2204 */ public function testSomethingElse() { } }
特定のグループに属するテストのみを選んで実行するには、
コマンドラインのテストランナーの場合は
--group
オプションあるいは --exclude-group
オプションを指定します。XML 設定ファイルの場合は、
それぞれ対応するディレクティブを指定します。
@large
アノテーションは、
@group large
のエイリアスです。
PHP_Invoker
パッケージがインストールされていて strict モードが有効な場合に、
large テストは実行時間が 60 秒を超えたら失敗します。
このタイムアウト時間は、XML 設定ファイルの
timeoutForLargeTests
属性で変更できます。
@medium
アノテーションは
@group medium
のエイリアスです。
medium テストは、@large
とマークしたテストに依存してはいけません。
PHP_Invoker
パッケージがインストールされていて strict モードが有効な場合に、
medium テストは実行時間が 10 秒を超えたら失敗します。
このタイムアウト時間は、XML 設定ファイルの
timeoutForMediumTests
属性で変更できます。
テストを別プロセスで実行するときに、
PHPUnit は親プロセスのグローバルな状態を保存しようと試みます。
親プロセスのすべてのグローバル状態をシリアライズし、
子プロセス内で最後にそれをアンシリアライズするのです。
しかし、親プロセスのグローバル状態の中にもしシリアライズできないものがあれば、
問題が発生します。この問題に対応するために、グローバル状態の保存を無効にすることができます。
そのために使うのが @preserveGlobalState
アノテーションです。
class MyTest extends PHPUnit_Framework_TestCase { /** * @runInSeparateProcess * @preserveGlobalState disabled */ public function testInSeparateProcess() { // ... } }
@requires
アノテーションを使うと、共通の事前条件
(たとえば PHP のバージョンや拡張モジュールのインストール状況)
を満たさないときにテストをスキップできます。
条件に指定できる内容やその例については 表 7.3 を参照ください。
テストクラス内のすべてのテストケースを、個別の PHP プロセスで実行するように指示します。
/** * @runTestsInSeparateProcesses */ class MyTest extends PHPUnit_Framework_TestCase { // ... }
注意: デフォルトで、PHPUnit は親プロセスのグローバルな状態を保存しようと試みます。 親プロセスのすべてのグローバル状態をシリアライズし、 子プロセス内で最後にそれをアンシリアライズするのです。 しかし、親プロセスのグローバル状態の中にもしシリアライズできないものがあれば、 問題が発生します。この問題に対応するために、グローバル状態の保存を無効にすることができます。 この問題の対処法については 「@preserveGlobalState」 を参照ください。
そのテストを個別の PHP プロセスで実行するように指示します。
class MyTest extends PHPUnit_Framework_TestCase { /** * @runInSeparateProcess */ public function testInSeparateProcess() { // ... } }
注意: デフォルトで、PHPUnit は親プロセスのグローバルな状態を保存しようと試みます。 親プロセスのすべてのグローバル状態をシリアライズし、 子プロセス内で最後にそれをアンシリアライズするのです。 しかし、親プロセスのグローバル状態の中にもしシリアライズできないものがあれば、 問題が発生します。この問題に対応するために、グローバル状態の保存を無効にすることができます。 この問題の対処法については 「@preserveGlobalState」 を参照ください。
@small
アノテーションは
@group small
のエイリアスです。
small テストは、@medium
や @large
とマークしたテストに依存してはいけません。
PHP_Invoker
パッケージがインストールされていて strict モードが有効な場合に、
small テストは実行時間が 1 秒を超えたら失敗します。
このタイムアウト時間は、XML 設定ファイルの
timeoutForSmallTests
属性で変更できます。
デフォルトでは、@medium
あるいは @large
のどちらかのアノテーションがないテストはすべて small と見なされます。
しかし、--group
およびそれに関連するオプションは、
明示的なアノテーションで small
とマークしているテストだけを small
と見なすことに注意しましょう。