FuelPHPをやってみる (7) - コントローラーテスト時の例外を無視してレスポンスを取る

2012-11-09T00:00:00+00:00 FuelPHP PHP

前にも書いたんですが、コントローラーテスト時にset_methodとかしても結局ルーティングに合わない場合等にはHttpNotFoundExceptionがスローされたりして結局レスポンス取れないっていう事があったのですが、んまぁ大体の言語には「このテストでは例外が出る」っていうのを前提にテストを書く(expectedException)というケースがありきたりだとは思いますが

例外うっせぇ、それでもレスポンスをちゃんとチェックしてえんだよクソが

って思う人もいるでしょう。という事でごちゃごちゃでまだ理解出来た訳じゃないのですが、いろいろ調べてみた。という事で例題的なサンプルのコントローラーが

fuel/app/classes/controller/home.php

<?php

class Controller_Home extends Controller {
    public function get_index() {
        $data["entries"] = Model_Items::find_all();

        $data["errors"] = Session::get_flash("validation_errors", array());

        throw new Exception("error");

        // return View::forge("home/index", $data);
    }
}

メソッドがget_indexになっているので、このリクエスト自体はHTTP/GETしか容認しないと思うのですが。で前にも書いたけど、このコントローラーテストする場合

fuel/app/tests/controller/test_home.php

<?php

class Test_Controller_Home extends TestCase {
    public function test_action_index() {
        $response = Request::forge("home/index")->set_method("POST")->execute()->response();
    }
}

としてもexecuteの時点でHttpNotFoundExceptionが発生する(本来は403エラーになるべきだと思うのだけど)。こっちが要求したいのは例外を起こさせる事ではなく例外が起きてもFurlCoreResponseが返ってきて欲しい場合。

で更にproduction環境上はExceptionを例外を発生させた場合にはHTTP/500エラーになる。そこら辺をテストするには現状のRequestクラスでは出来ないはず。恐らくはcurlドライバーでテストしても変わらない。本質はFuelCoreRequest#executeにあるはずなので。

という事でこれの例外をすべてラップしちゃってレスポンスを取るRequestクラスをでっち上げる

fuel/app/classes/http_request.php

<?php

class HttpRequest extends Request {
    public function execute($method_params = null) {
        try {
            parent::execute($method_params);
        } catch(Exception $e) {
            if ($e instanceof HttpException) {
                $this->response = $e->response();
            } else {
                $f = new HttpServerErrorException($e);

                $this->response = $f->response();
            }
        }

        return $this;
    }
}

ようはRequest#executeで実行する際に例外を処理しないから例外スローされちゃう訳だからそれをラップして例外をチェック。fuel/core/classes/httpexceptions.phpに定義されている例外クラスを確認すると

<?php

namespace Fuel\Core;


class HttpNotFoundException extends HttpException
{
    public function response()
    {
        return new Response(View::forge("404"), 404);
    }
}

class HttpServerErrorException extends HttpException
{
    public function response()
    {
        return new Response(View::forge("500"), 500);
    }
}

っつー感じになってる模様げなので、発生した例外がHttpException基底であるかをチャックして、それであればそのままレスポンスメソッドをRequest->responseにぶち込む。そうじゃなければ、HttpServerErrorExceptionでレスポンスを設定する

っていう方法を取る事でたとえHttpNotFoundExceptionなどによる例外発生が出た場合にでもレスポンスをチェック出来る(はず)

もちろん上に書いたように例外スローでもその例外スローをexpectedすれば良い。だけど、例外発生時のレスポンスのテストを行う際にはこういう手法を用いるとかで代用出来るのかも

FuelPHPをやってみる (6) - モデルテストとモック - FuelPHPをやってみる (5) - Migrationを使う -