LoginSignup
22
21

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-04-02

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

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

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メソッドをテストするとします。
※適当でごめんなさい

Hoge.php
<?php

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

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

HogeTest.php
<?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
ではでは。

22
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
21