2014年5月29日木曜日

[CakePHP]Controllerのテストで主要モデル以外のモデルのモックを作る方法

※CakePHP2.4.9の話

例えば、AmazonsControllerのテストの場合、

AmazonsControllerTest.php内
$this->controller = $this->generate('Amazons', array(
    'models' => array(
        'Amazon' => array('hardToTest')
    )
));
$this->controller->Amazon->expects($this->once())
        ->method('hardToTest')
        ->will($this->returnValue(true));

主要モデル(コントローラー名に名前が入るモデル)のAmazonモデルの場合は、こんな感じでモックを生成できる。(hardToTestというメソッドのモックを作りたい時)

でも、それ以外のモデル、例えば、Amazonモデルにアソシエーションで紐づくモデルやControllerの処理内でloadModel()したモデル、さらにそれにアソシエーションに紐づくモデルetcはこのやりかたで生成できない。

上記でいう、6行目のexpects()で下記のエラーが発生する。

Error: Call to a member function expects() on a non-object

これに対処する方法のひとつにテスト対象のControllerの$usesにモックを生成したいモデルを入れる、というものもある。ようは、モック化対象のモデルを主要モデルの一つにしちゃうという方法だ。これなら上記のような形で生成できる。
でもそもそもテストのためにプロダクトのコードに手を入れるのってやだよね。

そんな場合は、getMockForModel()を使う。これで簡単にControllerのテスト内で任意のモデルのモックを生成できる。

$this->Controller = $this->generate('Amazons');
$this->getMockForModel('Vote', array('hardToTest'))
        ->expects($this->any())->method('hardToTest');

上記で登場するVoteモデルはちなみにAmazonモデルには直接アソシエーションで紐づいていないモデルだ。Controllerの処理内でloadModelされるItemというModelにアソシエーションで紐づいているモデルである。

でも上記のコードでモックを生成することができる。
注意点としては、かならず1行目でControllerのモックを生成しておく必要があること。

余談だが、上記の$this->Controllerて変数はどんな変数名にしてもOK。$Amazonsにしてもいいし$aでも$bでもOK。generate()メソッドは自動的に$this->Controllerを生成してくれるみたいです。※参考 CakePHP 2.xのtestActionをちゃんと理解しよう

もう一つ余談ですが、当然ですが、モック化したメソッド以外のメソッドは本物のメソッド使ってくれるみたいですね。

0 件のコメント:

コメントを投稿