CakePHP3でControllerのテストを書く
そもそもなぜControllerのテストを書くか
私、正直テストコード書くの好きじゃないです。書かなくて済むなら書きたくない人(だって画面見てちゃんと確認すればいいじゃんの人)
勿論書くべきところは書きます。時と場合によるってやつですね。
で、割と大きめ~~(割とじゃねーなw)~~のプロジェクト(まだ開発中)で発生していることとして
- アクセス出来ちゃダメな画面(存在しないIDの詳細画面など)にURLで直で叩いたらアクセス出来てしまった
- 削除機能がgetでアクセス出来てしまった
なんてことがありまして、正直すべてのメソッドについて目視での網羅はどう考えても無理だと判断してControllerのテストをしょーがなく書くことにしました。
Controllerのテストは普通の大きくないプロジェクトじゃここまではやらないていいだろが私の意見です。
Controllerテストの書き方
<?php
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestCase;
class TopicsControllerTest extends IntegrationTestCase
{
public $fixtures = [
'app.topics'
];
/**
* Test view method
*/
public function testView()
{
// IDなしはエラー
$this->get('/topics/view');
$this->assertResponseError();
// 存在するデータはOK
$this->get('/topics/view/1');
$this->assertResponseOk();
// 存在しないデータはOK
$this->get('/topics/view/2');
$this->assertResponseError();
}
/**
* Test delete method
*/
public function testDelete()
{
// getでのアクセスはエラー
$this->get('/topics/delete/1');
$this->assertResponseError();
// IDなしはエラー
$this->post('/topics/delete');
$this->assertResponseError();
// 存在するデータはOK(削除後リダイレクトするのでOkではなくSuccess)
$this->post('/topics/delete/1');
$this->assertResponseSuccess();
// 存在しないデータはOK
$this->post('/topics/delete/2');
$this->assertResponseError();
// postは第二引数に配列でpostデータを記載できます。
}
}
まぁシンプルに書けます。
ログイン時など、セッションを使いたいときは
<?php
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestCase;
class TopicsControllerTest extends IntegrationTestCase
{
/**
* setUp method
*/
public function setUp()
{
parent::setUp();
// id 1でログインしているものとする
$result['id'] = 1;
// セッションに突っ込む
$this->session(['Auth' => [
'Admin' => [
$result
]
]]);
}
// 以下略
}
みたいな感じでやってあげればOKです。
requestをいじりたいとき
実際にURLを叩いているわけではないので、実際のリクエストからはパラメータが不足しています。
例えば実際にURLを叩いた際にはある$this->request->webroot
というパラメータはControllerテストの際にはrequestには含まれません。
そういったパラメータが必要な場合は
<?php
namespace App\Test\TestCase\Controller;
use Cake\TestSuite\IntegrationTestCase;
class TopicsControllerTest extends IntegrationTestCase
{
/**
* _buildRequest
*/
protected function _buildRequest($url, $method, $data)
{
$request = parent::_buildRequest($url, $method, $data);
$request->webroot = '/hoge/';
return $request;
}
// 以下略
}
コア読んでそれっぽいのがあった。多分やっていいと思うんだけど・・・。
まぁテスト実行時にrequestをいじるのは可能ってことで。
おまけ
テストコード書く際に、規模が大きくなってくるとFixtureで書いていると、MigrationとFixtureの二重管理とかなってつらたんなのでFixtureを使わずにMigrationを走らせたりしてます。
Seedsはテスト用のSeedsを別に準備するような感じですね。
その辺のmigration/Seedsセットが走るシェルを準備してexec
でぶっ叩いてます。(やや手抜きw)
まとめ
このくらいのテストなら、まぁ書けた。
でも、登録画面でpostした際の挙動とか書き始めると割とキリがない。
まだテストコードをどの辺まで書くべきなのかが個人的には見えてないなぁ・・・。(少なくとも盲目的に全部書くはやりたくない)