CakePHP&PHPUnitのsetUp・tearDownの挙動の細かい話


はじめに

これはCakePHP Advent Calendar 2017の11日目の記事です。
おはようございます、@Khigashiguchiです。
普段の業務でCakePHPを書いています。
業務中でちょっと詰まったときに調べたテストのこと、特にsetUp・tearDownの挙動を書き残してみようと思います。

目次

  • 環境情報
  • 背景
  • CakePHPの中身
  • 調査結果
  • 最後に

環境情報

  • PHP 5.3
  • CakePHP 2.3
  • PHPUnit 3.7

背景

Controllerのテストを書いていた時、ふと以下のようなことをしたいと思いました。
「テスト実行前に、Configureの中身を一部書き換えておきたい。」

pubic class HogehogeControllerTestCase extends ControllerTestCase
{
    public function setUp()
    {
        parent::setUp();
        // Configureの中身を書き換えたい
        if (Configure::check('Debug.host')) {
            $this->origin_host = Configure::read('Debug.host');
        }
        Configure::write('Debug.host', 'localhost');
    }


    public function tearDown()
    {
        parent::tearDown();
        // HERE: 書き換えたConfigureを元の状態に戻す

    }

このときにtearDown()で明示的にConfigureの中身を戻すような処理は書いた方がいいんだろうか。
どうすべきか迷ったので、CakePHPの中身を見てみました。

CakePHPの中身

CakePHPがoverrideしているsetUp()・tearDown()メソッドは、lib/Cake/TestSuite/CakeTestCase.php内にあります。

setUp()

/**
 * Setup the test case, backup the static object values so they can be restored.
 * Specifically backs up the contents of Configure and paths in App if they have
 * not already been backed up.
 *
 * @return void
 */
    public function setUp() {
        parent::setUp();

        if (empty($this->_configure)) {
            $this->_configure = Configure::read();
        }
        if (empty($this->_pathRestore)) {
            $this->_pathRestore = App::paths();
        }
        if (class_exists('Router', false)) {
            Router::reload();
        }
    }

PHPUnitのsetUp()を呼び出してから、実行前の状態をインスタンス変数に格納しています。
テスト実行前のConfigureを Configure::read() でインスタンス変数に格納しています。

tearDown()

/**
 * teardown any static object changes and restore them.
 *
 * @return void
 */
    public function tearDown() {
        parent::tearDown();
        App::build($this->_pathRestore, App::RESET);
        if (class_exists('ClassRegistry', false)) {
            ClassRegistry::flush();
        }
        if (!empty($this->_configure)) {
            Configure::clear();
            Configure::write($this->_configure);
        }
        if (isset($_GET['debug']) && $_GET['debug']) {
            ob_flush();
        }
    }

setUpと同じく、PHPUnitのtearDown()を呼び出してから、以下の後片付けをしてくれてます。

  • ClassRegistryの片付け
    ClassRegistry::initでModelを読んだ場合は、この処理で後片付けしてくれそうです。

  • Configureを実行前の状態に戻す
    setUp()で取っておいた$this->_configureを使って実行前の状態に戻しています。

  • bufferをFlush

調査結果

ConfigureはCakePHPの機構の中でConfigureを元どおりに戻してくれそうなので冒頭のコードでは、tearDownで何もしなくても大丈夫そうです。

最後に

悩んだときはコードを読むのが一番早いですね。
来年も、バージョンはしっかり上げつつCakePHPer頑張ります!

以上