第13章 PHPUnit の実装

PHPUnit の実装はちょっと見慣れないものでしょう。 通常のアプリケーションでは保守しづらくなるようなテクニックを使用したりしています。 PHPUnit がテストを実行する仕組みを知っておくと、 あなたがテストを書く際に役立つこともあるでしょう。

個々のテストは PHPUnit2_Framework_Test のオブジェクトで表され、テストを実行するには PHPUnit2_Framework_TestResult のオブジェクトが必要です。PHPUnit2_Framework_TestResult オブジェクトが PHPUnit2_Framework_Test オブジェクトの run() メソッドに渡され、 このメソッドが実際のテストメソッドを実行します。そこで発生した例外を PHPUnit2_Framework_TestResult オブジェクトに報告します。 これは、Smalltalk の世界では Collecting Parameter と呼ばれているお決まりのパターンです。複数のメソッドの結果 (ここでは、各テストを起動する run() メソッドの結果) を一箇所にまとめたい場合は、メソッドにパラメータを追加すればそれが結果を集めてくれるのです。 Erich Gamma と Kent Beck の "JUnit: A Cook's Tour" [GammaBeck1999] や Kent Beck の "Smalltalk Best Practice Patterns" [Beck1997] [Beck1997-ja] を参照ください。

PHPUnit がテストを実行するしくみをより深く探るため、 例13.1「EmptyTest クラス」 のようなテストクラスを考えてみましょう。

例13.1 EmptyTest クラス

<?php
require_once 'PHPUnit2/Framework/TestCase.php';
 
class EmptyTest extends PHPUnit2_Framework_TestCase {
    private $emptyArray = array();
 
    public function testSize() {
        $this->assertEquals(0, sizeof($this->emptyArray));
    }
 
    public function testIsEmpty() {
        $this->assertTrue(empty($this->emptyArray));
    }
}
?>


テストが実行されるときに PHPUnit がまず行うのは、テストクラスを PHPUnit2_Framework_Test オブジェクトに変換することです。 ここでは、PHPUnit2_Framework_TestSuite には 図13.1「実行しようとしているテスト」 に見られるように 2 つの EmptyTest インスタンスが含まれます。

図13.1 実行しようとしているテスト

実行しようとしているテスト


PHPUnit2_Framework_TestSuite の実行時には、各 EmptyTest が順に実行されます。その中では各自の setUp() メソッドが実行され、各テストについて 図13.2「テストを実行した後の fixture の状態」 に見られるような新しい $emptyArray を作成します。 こうすることで、あるテストが配列を変更したとしても それが他のテストに影響を及ぼさないようになります。 仮にグローバル変数やスーパーグローバル変数 ($_ENV など) を変更したとしても、それは他のテストには影響を及ぼしません。

図13.2 テストを実行した後の fixture の状態

テストを実行した後の fixture の状態


つまり、テストが実行される際には、ひとつのテストケースクラスが 2 段階のオブジェクトツリーになるということです。各テストは setUp() で作成された自分自身のコピーの上で実行され、テストは完全に独立して実行されます。

PHPUnit は、リフレクションを使用してインスタンス変数 $name からメソッド名を取得し、そのテストメソッドを実行します。これは、Smalltalk の世界では Pluggable Selector と呼ばれているお決まりのパターンです。 Pluggable Selector を使用することでテストをよりシンプルに書くことができますが、 その代わりコードを見ただけではどのメソッドが実行されるのかがわからなくなります。 実行されるメソッドを知るには、実行時のデータの値を調べなければならないのです。