概要
Cakephp3で edit アクションを作るとき、存在しないデータを editしようとすると
RecordNotFoundException 例外が発生します。
例えば、http://....../controller/edit/99999999
にアクセスすると、Cakeのエラー画面になります。
Unitテストのログも下記のようなものが出てきます。
1) App\Test\TestCase\Controller\SomeControllerTest::testEdit
Cake\Datasource\Exception\RecordNotFoundException: Record not found in table "something" in /var/www/app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php:410
Stack trace:
#0 /var/www/app/vendor/cakephp/cakephp/src/ORM/Table.php(1201): Cake\ORM\Query->firstOrFail()
#1 /var/www/app/src/Controller/SomeController.php(86): Cake\ORM\Table->get(Array, Array)
#2 [internal function]: App\Controller\SomeController->edit('10000')
例外を抑制するにはどうしたらよいか、
例外が出る場合のUnitテストはどうするのか
例外でUnitテストが途中で止まるのをなんとかしたい、
ということでまだスッキリ解決していないものの現状を書いてみました。
問題点
・例外の出方がイマイチ不明で、テストの時の挙動も不明。
例えば、
- Controllerの中でTry-catch で例外を捕捉できるが
$this->SomeTable->get($id, [
'contain' => []
]);
- Table の中では例外が捕捉できない。
$this->get($id, [
'contain' => []
]);
Tableの中で例外が捕捉できないなら、getメソッドを自作すればよいかも、と思ったものの try-catch はapp/vendor/cakephp/cakephp/src/ORM/Table.php
にあるgetの中には存在せず、
app/vendor/cakephp/cakephp/src/ORM/Behavior/TreeBehavior.php
の中でthrowしていたり、
app/vendor/cakephp/cakephp/src/Datasource/QueryTrait.php
の中でthrowしていたり、
かなり深い部分を探る必要がありそうです。
つまりTableの中で例外を捕捉せず、コントローラ側で RecordNotFoundException例外などをTry-catchすべきなのでしょう。
テストでの挙動
Controller のテスト
アサーションの結果と違う場合には例外が出てテストが途中で終了し、
アサーション通りだとテストが成功するようです。
// 下記のように書くと例外は確認出来ず
$this->assertResponseError();
// 下記のように書くと例外が発生する。
$this->assertResponseOk();
//この例外が発生しているところで
$this->expectException('Cake\Datasource\Exception\RecordNotFoundException');
$this->assertResponseOk();
// あるいはアノテーションで
/**
* @expectedException \Cake\Datasource\Exception\RecordNotFoundException
*/
public function someEditTest(){
..........................
$this->assertResponseOk();
というようにテスト関数の前に書いても例外は発生してテストが中断します。
Tableのテスト
例外は、expectException
で宣言しておくとテストが止まらないものの、
例外が発生した箇所より後は何も実行されません。
$this->expectException('Cake\Datasource\Exception\RecordNotFoundException');
debug('このデバッグ文は表示されますが');
$this->SomeTables->dosomething($data);
debug('このデバッグ文は表示されません');
//このAssertionも実行されません。
$this->assertFalse($result);
結論
- 例外をTry-catch するなら、Controllerでやると良さそう。
- テストでは、Controllerのテストで例外が出ないようにし、
- Tableのテストでは例外が出ることを確認できる。