PHPUnitでSingleton+staticメソッドをテストするケース
<?php
abstract class Phest_Assert implements Phest_Assert_Interface {
public static function getTester() {
return Phest_Context::getInstance();
}
public static function getReporter() {
$tester = static::getTester();
if (!($tester instanceof Phest_Context)) {
throw new Phest_Exception("invalid test context");
}
$reporter = $tester->getReporter();
if (!($reporter instanceof Phest_Report)) {
throw new Phest_Exception("invalid report instance");
}
return $reporter;
}
public static function report($testSuccessful, $e = null) {
static::getReporter()->report($testSuccessful, $e);
}
}
みたいなクラスがあったと場合にgetReporterメソッドの内部をMockを使ってテストする場合には
- getTesterが返すオブジェクトのgetReporterメソッドが返す値を変更する
- getTesterが返す値をMockで書き換える(staticメソッド。及び返す値はSingleton)
という事をしなければならない。でテストフレームワークはPHPUnitなので、そこら辺は問題無く出来る模様
<?php
class Phest_Assert_Dummy extends Phest_Assert {
public static function evaluate($expectedValue, Phest_Assert_Matcher $matcher) {
}
}
class Phest_Assert_TestCase extends PHPUnit_Framework_TestCase {
/**
* @expectedException Phest_Exception
* @expectedExceptionMessage invalid report instance
*/
public function test_getReporter_getTester_call_getReporter_is_null() {
$ctxMock = $this->getMockBuilder(
"Phest_Context",
array("getReporter")
)->disableOriginalConstructor()->getMock(); // getTesterが返すオブジェクトはSingletonなのでデフォルトのコンストラクタを実行しない方式で物区オブジェクトを取得する
$ctxMock->expects(
$this->any()
)->method(
"getReporter"
)->will($this->returnValue(null)); // 上記の物区オブジェクトのgetReporterメソッドが返す値をnullにする
$mock = $this->getMock("Phest_Assert_Dummy", array("getTester"));
$mock->staticExpects(
$this->any()
)->method(
"getTester"
)->will(
$this->returnValue($ctxMock)
); // getTesterメソッドが返す値は上記で生成したモックオブジェクトを返すように設定する
$mock::getReporter(); // 例外発生する
}
}
っていう感じでMockBuilderとかを使ってSingletonなクラスでコンストラクタ実行をしないようにしてそのクラスのモックオブジェクトを生成出来る模様。ちなみに
$mock = $this->getMock("Phest_Context", array("getReporter"), "", false);
でもgetMockBuilderを使うのと同様な感じで出来る模様