ci-phpunit-testでsingletonなクラスを呼び出してるメソッドをテストする

  • 5
    Like
  • 0
    Comment
More than 1 year has passed since last update.

最近テストで使ってる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の組み合わせです。

さっそくコード見てみましょう。

application/libraries/DateTimeManager.php
<?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()メソッドをテストするとします。
※適当でごめんなさい

application/libraries/Hoge.php
<?php

class Hoge
{
    public function getFuga()
    {
        $dateTime = DateTimeManager::singleton()->getDateTime();
        return $dateTime;
    }
}

テストクラスはこうなります。

application/tests/libraries/Hoge_test.php
<?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
ではでは。

参考文献