新しいテストケースクラスを作成する際には、 これから書くべきテストの内容をはっきりさせるために、 まず最初は以下のような空のテストメソッドを書きたくなることでしょう。
public function testSomething() { }
しかし、PHPUnit フレームワークでは空のメソッドを「成功した」
と判断してしまうという問題があります。このような解釈ミスがあると、
テスト結果のレポートが無意味になってしまいます。
そのテストがほんとうに成功したのか、
それともまだテストが実装されていないのかが判断できないからです。
実装していないテストメソッドの中で $this->fail()
をコールするようにしたところで事態は何も変わりません。
こうすると、テストが「失敗した」と判断されてしまいます。
これは未実装のテストが「成功」と判断されてしまうのと同じくらいまずいことです
(訳注: レポートを見ても、そのテストがほんとうに失敗したのか、
まだ実装されていないだけなのかがわかりません)。
テストの成功を青信号、失敗を赤信号と考えるなら、
テストが未完成あるいは未実装であることを表すための黄信号が必要です。
そのような場合に使用するインターフェイスが
PHPUnit_Framework_IncompleteTest
で、
これは未完成あるいは未実装のテストメソッドで発生する例外を表すものです。
このインターフェイスの標準的な実装が
PHPUnit_Framework_IncompleteTestError
です。
例 7.1
では SampleTest
というテストケースクラスを定義しています。
便利なメソッド markTestIncomplete()
(これは、自動的に PHPUnit_Framework_IncompleteTestError
を発生させます) をテストメソッド内でコールすることで、
このメソッドがまだ完成していないことをはっきりさせます。
例 7.1: テストに未完成の印をつける
<?php class SampleTest extends PHPUnit_Framework_TestCase { public function testSomething() { // オプション: お望みなら、ここで何かのテストをしてください。 $this->assertTrue(TRUE, 'これは動いているはずです。'); // ここで処理を止め、テストが未完成であるという印をつけます。 $this->markTestIncomplete( 'このテストは、まだ実装されていません。' ); } } ?>
未完成のテストは、PHPUnit のコマンドライン版テストランナーでは以下のように
I
で表されます。
phpunit --verbose SampleTest
PHPUnit 4.2.0 by Sebastian Bergmann.
I
Time: 0 seconds, Memory: 3.95Mb
There was 1 incomplete test:
1) SampleTest::testSomething
このテストは、まだ実装されていません。
/home/sb/SampleTest.php:12
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 1, Incomplete: 1.
表 7.1 に、テストを未完成扱いにするための API を示します。
表7.1 未完成のテスト用の API
メソッド | 意味 |
---|---|
void markTestIncomplete() | 現在のテストを未完成扱いにします。 |
void markTestIncomplete(string $message) | 現在のテストを未完成扱いにします。それを説明する文字列として $message を使用します。 |
すべてのテストがあらゆる環境で実行できるわけではありません。 考えてみましょう。たとえば、データベースの抽象化レイヤーを使用しており、 それがさまざまなドライバを使用してさまざまなデータベースシステムを サポートしているとします。MySQL ドライバのテストができるのは、 当然 MySQL サーバが使用できる環境だけです。
例 7.2
に示すテストケースクラス DatabaseTest
には、
テストメソッド testConnection()
が含まれています。
このクラスのテンプレートメソッド setUp()
では、
MySQLi 拡張モジュールが使用可能かを調べたうえで、もし使用できない場合は
markTestSkipped()
メソッドでテストを省略するようにしています。
例 7.2: テストを省略する
<?php class DatabaseTest extends PHPUnit_Framework_TestCase { protected function setUp() { if (!extension_loaded('mysqli')) { $this->markTestSkipped( 'MySQLi 拡張モジュールが使用できません。' ); } } public function testConnection() { // ... } } ?>
飛ばされたテストは、PHPUnit のコマンドライン版テストランナーでは以下のように
S
で表されます。
phpunit --verbose DatabaseTest
PHPUnit 4.2.0 by Sebastian Bergmann.
S
Time: 0 seconds, Memory: 3.95Mb
There was 1 skipped test:
1) DatabaseTest::testConnection
MySQLi 拡張モジュールが使用できません。
/home/sb/DatabaseTest.php:9
OK, but incomplete or skipped tests!
Tests: 1, Assertions: 0, Skipped: 1.
表 7.2 に、テストを省略するための API を示します。
表7.2 テストを省略するための API
メソッド | 意味 |
---|---|
void markTestSkipped() | 現在のテストを省略扱いにします。 |
void markTestSkipped(string $message) | 現在のテストを省略扱いにします。それを説明する文字列として $message を使用します。 |
ここまでに示したメソッドに加えて、
@requires
アノテーションを使って共通の事前条件を記述することもできます。
表7.3 @requires の例用例
型 | 取り得る値 | 例 | 別の例 |
---|---|---|---|
PHP | PHP のバージョン | @requires PHP 5.3.3 | @requires PHP 5.4-dev |
PHPUnit | PHPUnit のバージョン | @requires PHPUnit 3.6.3 | @requires PHPUnit 4.2 |
OS | PHP_OS にマッチする正規表現 | @requires OS Linux | @requires OS WIN32|WINNT |
function | function_exists に渡せるパラメータ | @requires function imap_open | @requires function ReflectionMethod::setAccessible |
extension | 拡張モジュール名 | @requires extension mysqli | @requires extension curl |
例 7.3: @requires を使ったテストケースのスキップ
<?php /** * @requires extension mysqli */ class DatabaseTest extends PHPUnit_Framework_TestCase { /** * @requires PHP 5.3 */ public function testConnection() { // このテストには mysqli 拡張モジュールと PHP 5.3 以降が必須です } // ... その他のすべてのテストには mysqli 拡張モジュールが必須です } ?>
特定のバージョンの PHP でしか使えない構文を利用する場合は、 「テストスイート」 にあるように XML 設定ファイルでのバージョン依存のインクルードを検討しましょう。