Technote

by sizuhiko

テスト駆動web開発勉強会 Vol.1で発表しました

2014/3/18にコワーキングスペース茅場町Co-Edoで開催された「テスト駆動web開発勉強会 Vol.1」で「Webアプリケーションテスト手法2014」の発表をしました。

第一回目ということと、1時間枠と限られた時間の中でCakePHPとJavaScriptについてのテストの話をしたので、ざっくりした内容となっています。

今後ハンズオンなども計画しているようなので、DoorKeeperのページをチェックしておくと良いかなーと思います。 また当日は「Java,PHPエンジニアの派遣、求人を探すならJapheego(ジャフィーゴ)」さんに懇親会スポンサーになっていただき、美味いビールとSUBWAYのサンドイッチをいただきました。感謝! 勉強会の懇親会はピザが多いのですが、連続すると飽きるのでたまにはSUBWAYのデリバリーとか良いと思いますよ!(SUBWAY大好きです)

To see files inline you need to enable JavaScript.
Yahoo has some instructions for enabling JavaScript if you’re unsure how to do it.

Download this file

最後に、当日紹介したサンプルのCakePHPテストコードを掲載しておきます。

モデルのテスト例:
<?php
class PostTest extends CakeTestCase {
    public $fixture = ['app.Post', 'app.Comment'];

    public function setUp() {
        $this->model = ClassRegistry::init('Post');
        $this->model = $this->getMockForModel('Post');
        $this->model = $this->getMockForModel('Post', ['save']);
    }

    public function testタイトルがない場合はバリデーションエラーになること() {

    }
    public function testデータベースへの保存に失敗した場合はfalseが戻ること() {

    }
    public function testデータベースへの保存に成功した場合はtrueが戻ること() {

    }
    public function testデータベースに新規登録できること() {

    }
}

モデルの初期化方法には3つのやり方があり、通常はClassRegistry::init()で良いのですが、モデルをモックしたい場合はgetMockForModel()というCakeTestCaseが用意してくれているモデル専用のモックジェネレータを使います。第二引数にメソッドの配列を指定するとパーシャルモックとなり、特定のメソッドのみモックします。

コントローラのテスト例:
<?php
class PostsControllerTest extends ControllerTestCase {
    public function setUp() {
        $this->controller = $this->generate('Posts',[
            'components' => [
                'Session',
                'RequestHandler'=>['isPost'],
            ],
            'models' => [
                'Post' => ['findById','delete'],
            ],
            'methods' => [
                'redirect', 'render',
            ],
        ]);
    }

    /**
     * @expectedException NotFoundException
     */
    public function test存在しない記事を表示するとNotFound例外になること() {
        $this->testAction('/posts/view/999');
    }
    /**
     * @expectedException BadRequestException
     */
    public function test保存がPOST以外で呼び出されたらBadResuest例外になること() {
        $this->testAction('/posts/save/1', ['method' => 'get']);
    }
    public function test削除が成功したらindexにリダイレクトする() {
        $this->controller->Post->expects($this->once())->method('delete')
                ->with($this->equalTo(1))->will($this->returnValue(true));
        $this->controller->expects($this->once())->method('redirect')
                ->with($this->equalTo('index'));
        $this->testAction('/posts/delete/1', ['method' => 'delete']);
    }
    public function test新しいトピックを追加できたら画面にメッセージが戻ること() {

    }
}

コントローラのテストをするとき、testActionメソッドを呼び出すわけですが、そのときコントローラ自体をモックするにはControllerTestCaseが用意してくれているコントローラ専用のモックジェネレータであるgenerate()を利用します。generateで作成したインスタンスをテストケースクラスのcontrollerメンバ変数にセットすることでControllerTestCaseがURLからディスパッチするときに、このモックオブジェクトを利用してくれます。

コントローラから依存関係にある、コンポーネント、モデルについてそれぞれサンプルのようにモックでき、コントローラ自体のメソッドもmethodsに列挙することでモックできます。例えばredirect()render()などがよく使われると思います。