はじめに
PHPで書いたプログラムの単体テスト(自動テスト)は通常PHPUnitで実装することになります。
その際にテスト対象となるPHPのクラスはどのように書いてもテストできるわけではなく、一定の条件を満たす必要があります。
主に注意すべきは3点です。
- コンストラクタ
- ローカル変数の扱い
- 静的関数、プロパティの扱い
基本的にはPHPUnitが提供しているMockに置き換えられるかどうかというところが焦点となります。
コンストラクタで複雑な処理を行わない
PHPに限らず大抵のオブジェクト指向のプログラミング言語でもそうなのですが、コンストラクタは他のメソッドよりも制御が難しく、自動テストを記述するのも難しいです。
コンストラクタ内で複雑な処理を実装してしまうと、引数に与えるオブジェクトを除いてMock化することもできないため、テストが記述不能になる可能性が高くなります。
コンストラクタの単体テストが記述できないようなclassの場合、ReflectionClass::newInstanceWithoutConstructor()でコンストラクタを迂回してテスト用のインスタンスを作るといった回避策を取ることもあるでしょう。ただしPHP > 5.4以上ですが。
メソッド内のローカルでnewしない
テスト対象のメソッド内のローカル変数として、外部のクラスのインスタンスを生成していたりすると、そのメソッドはテストを実装不能になります。なぜならば他のクラスのインスタンスが生成された環境であるため、そのクラスのプログラムも動作してしまい、単体テストでなくなってしまうからです。(それは結合テストです)
これは直接newで生成する場合以外も、SomeDao::getInstance()等の静的メソッドでインスタンスを取ってくるケースでも同じことになります。
この問題の回避策としては、外部クラスのインスタンスは一旦全てプロパティに代入し、プロパティ越しにアクセスすることでローカル変数でなくしてしまうことです。
するとプロパティに設定されるはずの外部クラスのインスタンスはPHPUnitが提供するMockに置き換えることができるので、単体テストとして記述できるようになります。
静的関数、プロパティの扱い
静的関数のテストは実質的にそのクラスのインスタンスが存在しない環境(そのメソッド自体でインスタンスを作っている場合を除く)となりますが、基本的なアプローチはこれまでに書いたことと同じです。
ただし、静的関数ではそのクラスのインスタンス別の環境とはならず、システム全体で単一の環境となる(あるいは状態を持たない環境となる)ので、注意して実装する必要はあるでしょう。
以上