Home > CakePHP | PHP > CakePHP routes.phpの確認はユニットテストで

CakePHP routes.phpの確認はユニットテストで

  • 2009-05-25 (月) 12:28
  • CakePHP | PHP
  • このエントリーをはてなブックマークに追加
この記事の所要時間: 423

第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:
  1. <?php
  2.   //
  3.   Router::connect('/:user_id/edit', array('controller' => 'user', 'action' => 'edit'));
  4.   Router::connect('/', array('controller' => 'top', 'action' => 'index'));
  5.   Router::connect('/:user_id/*', array('controller' => 'user', 'action' => 'index'));
  6.  
  7.   // Nothing
  8.   Router::connect('*', array('controller' => 'nothing'));
  9. ?>

最後はシステムが取るべきURL以外ならNot Foundを出すように設定しています。これにより想定外のコントローラーやアクションが実行されるのを防ぎます。

テストケースを作る

テストケースは何でも良いですが、とりあえず[app/tests/cases/url_routing.test.php]としておきましょう。スケルトンなソースは以下になります。

当然ながらこれはGREENでとおります。

PHP:
  1. <?php
  2. App::import('Core', 'Dispatcher');
  3.  
  4. class UrlRoutingTestCase extends CakeTestCase {
  5. }
  6. ?>

テストケースを書く ['/: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:
  1. <?php
  2.   public function test_parseParams_user_edit() {
  3.     $Dispatcher =& new Dispatcher();
  4.     $params = $Dispatcher->parseParams('/shin1x1/edit');
  5.     $this->assertIdentical('user', $params['controller']);
  6.     $this->assertIdentical('edit', $params['action']);
  7.     $this->assertIdentical('shin1x1', $params['user_id']);
  8.     $this->assertIdentical(array(), $params['pass']);
  9.     $this->assertIdentical(array(), $params['named']);
  10.   }
  11.  
  12. ?>

次は逆引きです。こちらはRouter::url()にパラメータを設定して、URLを求めています。Router::url()はパラメータからURLを生成するシーン(HelperとかController#redirect()とか)の裏で使われているメソッドなので、ここで求められるURLを確認すれば、実際のアプリケーションの挙動が確認できます。

↓では[controller='user'、action='edit', 'user_id'=shin1x1]というパラメータからどのようなURLが生成されるかをテストしています。

PHP:
  1. <?php
  2.   public function test_url_user_edit() {
  3.     $url = Router::url(array('controller' => 'user', 'action' => 'edit', 'user_id' => 'shin1x1'));
  4.     $this->assertIdentical('/shin1x1/edit', $url);
  5.   }
  6.  
  7. ?>

テストケースを書く ['/']

以下、同様です。正引き、逆引きをテストしています。

PHP:
  1. <?php
  2.   public function test_parseParams_user_top() {
  3.     $Dispatcher =& new Dispatcher();
  4.     $params = $Dispatcher->parseParams('/');
  5.     $this->assertIdentical($params['controller'], 'user');
  6.     $this->assertIdentical($params['action'], 'top');
  7.     $this->assertIdentical(array(), $params['pass']);
  8.     $this->assertIdentical(array(), $params['named']);
  9.   }
  10.   public function test_url_user_top() {
  11.     $url = Router::url(array('controller' => 'user', 'action' => 'top'));
  12.     $this->assertIdentical('/', $url);
  13.  
  14.     $url = Router::url(array('controller' => 'user', 'action' => 'top', 'user_id' => 'shin1x1'));
  15.     $this->assertIdentical('/user/top/user_id:shin1x1', $url);
  16.   }
  17. ?>

テストケースを書く ['/:user_id/*']

こちらも同様ですね。正引き、逆引きをテストしています。ここではnamedパラメータやQUERY_STRINGも簡易的にテストに入れています。

PHP:
  1. <?php
  2.   public function test_parseParams_user_index() {
  3.     $Dispatcher =& new Dispatcher();
  4.     $params = $Dispatcher->parseParams('/shin1x1');
  5.     $this->assertIdentical('user', $params['controller']);
  6.     $this->assertIdentical('index', $params['action']);
  7.     $this->assertIdentical('shin1x1', $params['user_id']);
  8.     $this->assertIdentical(array(), $params['pass']);
  9.     $this->assertIdentical(array(), $params['named']);
  10.  
  11.     $Dispatcher =& new Dispatcher();
  12.     $params = $Dispatcher->parseParams('/shin1x1/');
  13.     $this->assertIdentical($params['controller'], 'user');
  14.     $this->assertIdentical($params['action'], 'index');
  15.     $this->assertIdentical('shin1x1', $params['user_id']);
  16.     $this->assertIdentical(array(), $params['pass']);
  17.     $this->assertIdentical(array(), $params['named']);
  18.  
  19.     $Dispatcher =& new Dispatcher();
  20.     $params = $Dispatcher->parseParams('/shin1x1/a');
  21.     $this->assertIdentical($params['controller'], 'user');
  22.     $this->assertIdentical($params['action'], 'index');
  23.     $this->assertIdentical('shin1x1', $params['user_id']);
  24.     $this->assertIdentical(array('a'), $params['pass']);
  25.     $this->assertIdentical(array(), $params['named']);
  26.  
  27.     // namedパラメータ
  28.     $Dispatcher =& new Dispatcher();
  29.     $params = $Dispatcher->parseParams('/shin1x1/page:1');
  30.     $this->assertIdentical($params['controller'], 'user');
  31.     $this->assertIdentical($params['action'], 'index');
  32.     $this->assertIdentical('shin1x1', $params['user_id']);
  33.     $this->assertIdentical(array(), $params['pass']);
  34.     $this->assertIdentical(array('page' => '1'), $params['named']);
  35.   }
  36.   public function test_url_user_index() {
  37.     $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1'));
  38.     $this->assertIdentical('/shin1x1', $url);
  39.  
  40.     $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1', 'page' => 1));
  41.     $this->assertIdentical('/shin1x1/page:1', $url);
  42.  
  43.     $url = Router::url(array('controller' => 'user', 'action' => 'index', 'user_id' => 'shin1x1', 'page' => 1, '?' => array('mode' => 'hoge')));
  44.     $this->assertIdentical('/shin1x1/page:1?mode=hoge', $url);
  45.   }
  46. ?>

ユニットテストで楽々確認

というわけでユニットテストでroutes.phpをテストしてみました。

routes.phpの設定は凝っていくと色々な事ができて楽しいのですが、複雑にしていくとハマリがちです。特に条件が複雑になると意図せぬルーティングにマッチしてしまうことがままあります。

そんな時にテストを書いておけば、手軽に動作が確認できます。また、設定変更等に伴うデグレも簡単に判別することができます。例えば、冒頭にあるroutes.phpの内容も順番を入れ替えるとルーティングが変わるのですが、こういった事もテストを実行すれば、どのような挙動になっているかをすぐに判別がつきます。

URLルーティングのテストは書きやすいですし、書いていくと病みつきになりますよ。来月の自分のためにもバンバンテストを書いておきましょ-。

トラックバック:2

このエントリーのトラックバックURL
http://www.1x1.jp/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の逆ルーティングではまったのでちょ...

Home > CakePHP | PHP > CakePHP routes.phpの確認はユニットテストで

検索
フィード
メタ情報

Return to page top