第4回CakePHP勉強会@Tokyoでakiyanの男前な発表があったので、今後急増するであろうroutes.phpを極めていく人にオススメな確認方法をご紹介します。
routes.phpの確認にはユニットテストをオススメします。
routes.php設定でありがちなループとして、
- routes.phpを設定 -> ああ動いた
- routes.phpに設定追加 -> ああー動かない
- routes.phpを修正 -> あれ?前動いたところも動かなくなってるorz
というのがあるのですが、せっかくCakePHPにはユニットテスト機構があるのでテストを書いて動作確認をしましょう。
SimpleTestをダウンロードしていない人はダウンロードして、app/vendors/かvendors/に展開しておいて下さい。
routes.phpで設定する目標
Web2.0(最近あんまり聞かないですが。。。)なサイトではありがちなユーザIDを含めるURLを実現します。
URL | コントローラー | アクション | パラメータ |
---|---|---|---|
/ | TopController | index | none |
/shin1x1 | UserController | index | $params[‘user_id’] = ‘shin1x1’ |
/shin1x1/edit | UserController | edit | $params[‘user_id’] = ‘shin1x1’ |
それ以外 | NothingController | index | none |
routes.phpを仕様に合わせて設定しておきます。
<?php // Router::connect('/:user_id/edit', array('controller' => 'user', 'action' => 'edit')); Router::connect('/', array('controller' => 'top', 'action' => 'index')); Router::connect('/:user_id/*', array('controller' => 'user', 'action' => 'index')); // Nothing Router::connect('*', array('controller' => 'nothing')); ?>
最後はシステムが取るべきURL以外ならNot Foundを出すように設定しています。これにより想定外のコントローラーやアクションが実行されるのを防ぎます。
テストケースを作る
テストケースは何でも良いですが、とりあえず[app/tests/cases/url_routing.test.php]としておきましょう。スケルトンなソースは以下になります。
当然ながらこれはGREENでとおります。
<?php App::import('Core', 'Dispatcher'); class UrlRoutingTestCase extends CakeTestCase { } ?>
テストケースを書く [‘/:user_id/edit’]
まず[URLパターン=’/:user_id/edit’]のテストです。shin1x1がユーザIDとなっています。URLの正引き(URLからコントローラーやアクション、パラメータ等々を決定)はtest_parseParams~()に、URLの逆引き(コントローラーやアクション、パラメータ等々からURLを決定)はtest_url~()に実装しています。
URLの正引きではDispatcher#parseParams()に対象URLを与えて、その戻り値をassertで確認しています。実際の正引き処理はRouterクラスが行うのですが、戻り値の扱いやすさ、分かりやすさを考えてDispatcherを使っています。よりディープなテストをするならRouter::parse()を使った方が良いですね。
↓では[/shin1x1/edit]というURLに対してどのような正引きを行うかとテストしています。
<?php public function test_parseParams_user_edit() { $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/shin1x1/edit'); $this->assertIdentical('user', $params['controller']); $this->assertIdentical('edit', $params['action']); $this->assertIdentical('shin1x1', $params['user_id']); $this->assertIdentical(array(), $params['pass']); $this->assertIdentical(array(), $params['named']); } ?>
次は逆引きです。こちらはRouter::url()にパラメータを設定して、URLを求めています。Router::url()はパラメータからURLを生成するシーン(HelperとかController#redirect()とか)の裏で使われているメソッドなので、ここで求められるURLを確認すれば、実際のアプリケーションの挙動が確認できます。
↓では[controller=’user’、action=’edit’, ‘user_id’=shin1x1]というパラメータからどのようなURLが生成されるかをテストしています。
<?php public function test_url_user_edit() { $url = Router::url(array('controller' => 'user', 'action' => 'edit', 'user_id' => 'shin1x1')); $this->assertIdentical('/shin1x1/edit', $url); } ?>
テストケースを書く [‘/’]
以下、同様です。正引き、逆引きをテストしています。
<?php public function test_parseParams_user_top() { $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/'); $this->assertIdentical($params['controller'], 'user'); $this->assertIdentical($params['action'], 'top'); $this->assertIdentical(array(), $params['pass']); $this->assertIdentical(array(), $params['named']); } public function test_url_user_top() { $url = Router::url(array('controller' => 'user', 'action' => 'top')); $this->assertIdentical('/', $url); $url = Router::url(array('controller' => 'user', 'action' => 'top', 'user_id' => 'shin1x1')); $this->assertIdentical('/user/top/user_id:shin1x1', $url); } ?>
テストケースを書く [‘/:user_id/*’]
こちらも同様ですね。正引き、逆引きをテストしています。ここではnamedパラメータやQUERY_STRINGも簡易的にテストに入れています。
<?php public function test_parseParams_user_index() { $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/shin1x1'); $this->assertIdentical('user', $params['controller']); $this->assertIdentical('index', $params['action']); $this->assertIdentical('shin1x1', $params['user_id']); $this->assertIdentical(array(), $params['pass']); $this->assertIdentical(array(), $params['named']); $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/shin1x1/'); $this->assertIdentical($params['controller'], 'user'); $this->assertIdentical($params['action'], 'index'); $this->assertIdentical('shin1x1', $params['user_id']); $this->assertIdentical(array(), $params['pass']); $this->assertIdentical(array(), $params['named']); $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/shin1x1/a'); $this->assertIdentical($params['controller'], 'user'); $this->assertIdentical($params['action'], 'index'); $this->assertIdentical('shin1x1', $params['user_id']); $this->assertIdentical(array('a'), $params['pass']); $this->assertIdentical(array(), $params['named']); // namedパラメータ $Dispatcher =& new Dispatcher(); $params = $Dispatcher->parseParams('/shin1x1/page:1'); $this->assertIdentical($params['controller'], 'user'); $this->assertIdentical($params['action'], 'index'); $this->assertIdentical('shin1x1', $params['user_id']); $this->assertIdentical(array(), $params['pass']); $this->assertIdentical(array('page' => '1'), $params['named']); } public function test_url_user_index() { $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1')); $this->assertIdentical('/shin1x1', $url); $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1', 'page' => 1)); $this->assertIdentical('/shin1x1/page:1', $url); $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1', 'page' => 1, '?' => array('mode' => 'hoge'))); $this->assertIdentical('/shin1x1/page:1?mode=hoge', $url); } ?>
ユニットテストで楽々確認
というわけでユニットテストでroutes.phpをテストしてみました。
routes.phpの設定は凝っていくと色々な事ができて楽しいのですが、複雑にしていくとハマリがちです。特に条件が複雑になると意図せぬルーティングにマッチしてしまうことがままあります。
そんな時にテストを書いておけば、手軽に動作が確認できます。また、設定変更等に伴うデグレも簡単に判別することができます。例えば、冒頭にあるroutes.phpの内容も順番を入れ替えるとルーティングが変わるのですが、こういった事もテストを実行すれば、どのような挙動になっているかをすぐに判別がつきます。
URLルーティングのテストは書きやすいですし、書いていくと病みつきになりますよ。来月の自分のためにもバンバンテストを書いておきましょ-。
トラックバック:2
- このエントリーのトラックバックURL
- /blog/2009/05/cakephp_routers_php_unittest.html/trackback
- Listed below are links to weblogs that reference
- CakePHP routes.phpの確認はユニットテストで from Shin x blog
- trackback from Creazy! 09-05-27 (水) 13:28
-
極めたいw CakePHPのルーティング…
先週のCakePHP勉強会で、akiyanさんが routes.php に関す… (more…)
- trackback from kaz_29@はてな 10-02-18 (木) 21:48
-
[CakePHP]独自namedパラメータを使って逆ルーティング…
結構な忙しさなのですが、id:cakephperさんのTweetをみて妙に納得してしまったので、昨日はまってた事をまとめました。 CakePHP 1.2.5で開発中です。 namedパラメータはなかなかに便利なのですが、独自のnamedパラメータを使っているURLの逆ルーティングではまったのでちょ…