複雑なコンポーネントの単体テスト

環境: CakePHP1.3

単純な場合のテスト方法はクックブックに載っていますが、 より複雑な場合(コントローラや他のコンポーネントと連携する場合)は多くの準備作業が必要です。

その作業を省略するための ComponentTestCase クラスを作りました。ソースコードはとりあえずgistに置いておきます。

component_test_case.php

適当な場所 app/tests/libs などに置いてテストファイルの中で読み込んでください。

Fooコンポーネントをテストする場合の例は次のようになります。

require_once (TESTS .'libs/component_test_case.php');
 
class FooTestCase extends ComponentTestCase
{
  //コントローラの $components と全く同じ書式
  var $components = array('Foo' => array('a' => 'b'));
 
  function testAdd() {
    //$this->Controller でコントローラにアクセスできる
    $this->Controller->set(array('var1' => 1, 'var2' => 2));
 
    //$this->{コンポーネント名} でコンポーネントのインスタンスにアクセスできる
    $this->assertEqual(3, $this->Foo->add());
 
    //Fooの中で別のコンポーネントBarを読み込むことも可能
    //$components = array('Bar');
    $this->Foo->Bar->barmethod();
  }
}

モデルを使用することもできます。

class BarTestCase extends ComponentTestCase
{
  var $components = array('Bar');
  var $uses = array('User');
  var $fixtures = array('app.user');
 
  function testSomething() {
    //Barの中で、Controller経由でモデルにアクセスできる
    //$this->Controller->User
    $result = $this->Bar->doSomething();
  }
}

初期化パラメータを変えてテストしたい場合は _createController メソッドを使って直接 Controller を生成します。

class FooTestCase extends ComponentTestCase
{
  function testAdd() {
    $controller = $this->_createController(array('Foo' => array('c' => 'd')));
    $controller->set(array('var1' => 1, 'var2' => 2));
 
    //$this->{コンポーネント名} でアクセスすることはできない
    $this->assertEqual(3, $controller->Foo->add());
  }
}

デフォルトの初期化は startTest メソッドの中で行われるため、オーバーライドすることで柔軟な設定が可能です。 例えばメソッド名に _disableAutoLoad が入っているときだけ自動処理を停止する、といったことができます。

class FooTestCase extends ComponentTestCase
{
  var $defaultConfig = array('Foo' => array('a' => 'b'));
 
  function startTest($method) {
    if(preg_match('/_disableAutoLoad/', $method)) {
      $this->components = array();
    } else {
      $this->components = $this->defaultConfig;
    }
    parent::startTest($method);
  }
 
  function testAdd() {
    $this->Foo;
  }
 
  function testAdd2_disableAutoLoad() {
    $c = $this->_createController(array('Foo' => array('c' => 'd')));
  }
}

テストに使用するコントローラのクラスを切り替えることもできます。

class BarTestCase_TestController extends Controller
{
   //独自のテスト用ロジックを実装する...
}
 
class BarTestCase extends ComponentTestCase
{
  var $controllerClassName = 'BarTestCase_TestController';
}

TestCase内でのコントローラの初期化については Testing CakePHP Controllers the hard way | Mark Story を参考にしました。

4 Responses

  1. t_yodo より:

    便利な物をありがとうございます!

    さっそく実行してみたら、
    36行目でundefined function pluginSplit()と言われてしまいました・・・(;_;)

  2. tkyk より:

    コメントありがとうございます。

    pluginSplitはCakePHP 1.3にしか存在しない関数です。
    今のところ1.2でテストしている余裕がないので、
    > 環境: CakePHP1.3
    と書いてある通り、記事の内容は1.3前提になっています。

    pluginSplitのみに関して言えば、

    list($plugin, $key) = pluginSplit($key);

    となっているところを

    if (strpos($key, ‘.’) !== false) {
    list($plugin, $key) = explode(‘.’, $key);
    }

    にすれば動くはずです。
    しかし他のところで問題が出るかもしれません。

  3. t_yodo より:

    なるほど、ありがとうございます!

    1.3前提は承知の上でしたが、いろいろ追加変更あるんですね・・・

  4. [...] ComponentTestCaseを使ってメールの送信をテストする方法をまとめておきます。Qdmailerを使うことを前提としていますが、標準のEmailComponentなど他のコンポーネントでも同じようにテストできると思います。 [...]

Leave a Reply