最近テストで使ってるCodeIgniterとPHPUnit、ci-phpunit-testの組み合わせがいいので
CodeIgniterとPHPUnit、ci-phpunit-testを使ったテストについて書いてみたいと思います。
インストール方法や使い方に関しては「イマドキのCodeIgniterでPHPUnit入門 - Qiita」や「イマドキのCodeIgniterでPHPUnit入門(Composer不使用編) - Qiita」を参考にして頂ければと思います。
実行環境
- Mac OS X 10.10
- PHP 5.5.26
- CodeIgniter 3.0.1
- PHPUnit 4.8.5
- ci-phpunit-test 1.0.x@dev
レガシーなコードと戦う
singletonなクラスを呼び出してるメソッドをよく目にすると思うのですが(俺だけ?)、メソッドの中で呼び出してると、とてもテストしずらいですよね。
Mockery等でも一応静的メソッドのモックはできますがクラスが読み込まれてると使えない等制限がありますね。
そこでPHPUnitとci-phpunit-testの組み合わせです。
さっそくコード見てみましょう。
<?php
class DateTimeManager
{
static private $instance = null;
protected $timestamp;
public static function singleton()
{
if (! empty(self::$instance)) {
return self::$instance;
}
return self::$instance = new self();
}
private function __construct()
{
$this->timestamp = time();
}
public function getTimestamp()
{
return $this->timestamp;
}
public function getDateTime()
{
return date('Y/m/d H:i:s', $this->timestamp);
}
}
こんな時間を扱うクラスがあったとしてそれを呼び出すHoge
クラスのgetFuga()
メソッドをテストするとします。
※適当でごめんなさい
<?php
class Hoge
{
public function getFuga()
{
$dateTime = DateTimeManager::singleton()->getDateTime();
return $dateTime;
}
}
テストクラスはこうなります。
<?php
class Hoge_test extends TestCase
{
public function test_getFuga()
{
MonkeyPatch::patchMethod(
'DateTimeManager',
['getDateTime' => '2014/04/02 23:00:00']
);
MonkeyPatch::verifyInvokedOnce('DateTimeManager::singleton');
MonkeyPatch::verifyInvokedOnce('DateTimeManager::getDateTime');
$hoge = new Hoge();
$this->assertSame('2014/04/02 23:00:00', $hoge->getFuga());
}
}
テストメソッドの中でやってることは以下です。
-
MonkeyPatch::patchMethod()
メソッドで、DateTimeManager
クラスのgetDateTime()
メソッドの返り値を設定 -
MonkeyPatch::verifyInvokedOnce()
メソッドでメソッドの呼び出し確認 - テストメソッドを呼んでassertion
でいざテストするとちゃんとテストが成功します。
$ cd application/tests/
$ ../../vendor/bin/phpunit --debug libraries/Hoge_test.php
PHPUnit 4.8.5 by Sebastian Bergmann and contributors.
Starting test 'Hoge_test::test_getFuga'.
.
Time: 845 ms, Memory: 6.25Mb
OK (1 test, 3 assertions)
Generating code coverage report in Clover XML format ... done
Generating code coverage report in HTML format ... done
すごいですね。
こんな感じでレガシーコードと戦えます。
みなさん、CodeIgniterとPHPUnit、ci-phpunit-testに移行しましょうw
ではでは。