最近テストで使ってるCodeceptionとAspectMockの組み合わせがいいので
CodeceptionとAspectMockを使ったテストについて書いてみたいと思います。
インストール方法や使い方に関してはCodeception.com(公式)やAspectMock(GitHub)を参考にして頂ければと思います。
Qiitaにも参考になる記事がありますのでcodeceptionで検索してみてください。
実行環境
- CentOS 6.5
- PHP 5.4.26
- Codeception 1.8.3
- AspeckMock 0.4.1
※ CodeceptionとAspectMockはcomposer経由でinstallしてる前提です。
レガシーなコードと戦う
singletonなクラスを呼び出してるメソッドをよく目にすると思うのですが(俺だけ?)メソッドの中で呼び出してると、とてもテストしずらいですよね。
Mockery等でも一応静的メソッドのモックはできますがクラスが読み込まれてると使えない等制限がありますね。
そこでCodeceptionとAspectMockの組み合わせです。
さっそくコード見てみましょう。
<?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
use AspectMock\Test as test;
class HogeTest extends \Codeception\TestCase\Test
{
public function testGetFuga()
{
$dateTimeManagerInstance = test::double('DateTimeManager')->make();
$dateTimeManagerInstanceProxy = test::double($dateTimeManagerInstance, ['getDateTime' => '2014/04/02 23:00:00']);
$dateTimeManagerClassProxy = test::double('DateTimeManager', ['singleton' => $dateTimeManagerInstance]);
$hoge = new Hoge();
$this->assertSame('2014/04/02 23:00:00', $hoge->getFuga());
$dateTimeManagerClassProxy->verifyInvokedOnce('singleton');
$dateTimeManagerInstanceProxy->verifyInvokedOnce('getDateTime');
}
}
テストメソッドの中でやってることは以下です。
- 一個目のtest::doubleでコンストラクタを呼ばずにDateTimeManagerのインスタンスを取得
- 二個目のtest::doubleでそのインスタンスのgetDateTimeメソッドの返り値として時刻を設定
- 三個目のtest::doubleでsingletonメソッドの返り値として上記のインスタンスを設定
- テストメソッドを呼んでassertion
- モックメソッドの呼び出し確認
※verifyInvokedOnceの部分
でいざテストするとちゃんとテストが成功します。
$ ./vendor/bin/codecept run unit
Codeception PHP Testing Framework v1.8.3
Powered by PHPUnit 3.7.34 by Sebastian Bergmann.
Unit Tests (1) --------------------------------------------
Trying to test get fuga (HogeTest::testGetFuga) Ok
-----------------------------------------------------------
Time: 2.73 seconds, Memory: 70.50Mb
OK (1 test, 1 assertion)
すごいですね。
こんな感じでレガシーコードと戦えます。
みなさん、CodeceptionとAspeckMockに移行しましょうw
ではでは。