Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

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

最近テストで使ってる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
ではでは。

参考文献

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
5
Help us understand the problem. What are the problem?