テスト時のredirect()やcakeError() の結果を拾う。+ DebugKit使用時も。
前提
- CakePHP 1.2.7 を使用。
- cake testsuite app all のテストを対象
- Core や App に手を加えたくない。
- DebugKit 使用時も使いたい。(SqlLogPanel::beforeRender() の ob_start() から結果が返らなくなる)
関連URL
- CakeTestCaseでtestActionを実行すると別のページにリダイレクトされちゃう問題
- http://d.hatena.ne.jp/itmsc/20091001/1254374271
- app/app_controller.php の拡張
- テストの為に、拡張するのは躊躇われる。
- http://d.hatena.ne.jp/itmsc/20091001/1254374271
- [cakephp]testActionでredirectするアクションをテストする方法
- cakephp1.2でControllerをテストする際のredirectとcakeErrorアクションの取扱い
やること
- 関連URLの「CakeTestCaseでtestActionを実行すると別のページにリダイレクトされちゃう問題」のようにredirect() や cakeError() の処理を途中で中断させる。
具体的に。
- cake/console/cake を実行した際、cake/console/cake.php が呼ばれる
- 「testsuite」を処理するために、「testsuite.php」を呼ぼうとする
- App や Core 、vendors を順に探索して、「testsuite.php」を探す
- 独自に app/vendors/shells/testsuite.php を設置すると、cake/console/libs/testsuite.php の代わりに読み込まれる
- app/vendors/shells/testsuite.php では、独自に設置した app/libs/controller/controller.php を呼び、本来の testsuite.php を呼ぶ。
- app/libs/controller/controller.php では、 file_get_contents で、core/libs/controller/controller.php の内容を取得し、 redirect()、cakeError() の処理を置換し、コンポーネントの DebugKit を解除する。最後にeval()で読み込む。
Source
[app/vendors/shells/testsuite.php]
<?php App::import(null, 'Controller', true, array(APP . 'libs/controller')); foreach (array(VENDORS . 'shells/testsuite.php', CONSOLE_LIBS . 'testsuite.php') as $path) { if (file_exists($path)) { require $path; break; } }
[app/libs/controller/controller.php]
<?php $construct = ' if (defined("TEST_CAKE_CORE_INCLUDE_PATH")) { $index = array_search("DebugKit.Toolbar", $this->components); if ($index !== false) { unset($this->components[$index]); $this->components = array_merge(array_diff($this->components, array())); } } '; $cakeError = ' function cakeError($method, $messages = array()) { if (defined("TEST_CAKE_CORE_INCLUDE_PATH")) { $return = array( "function" => "cakeError", "method" => $method, "messages" => $messages, "session" => $this->Session->read() ); $this->set("return", $return); $this->render(null, null, TESTS . "views" . DS . "redirect.ctp"); return true; } return parent::cakeError($method, $messages); } '; $redirect = ' if (defined("TEST_CAKE_CORE_INCLUDE_PATH")) { $return = array( "function" => "redirect", "url" => $url, "status" => $status, "exit" => $exit, "session" => $this->Session->read() ); $this->set("return", $return); $this->render(null, null, TESTS . DS . "views" . DS . "redirect.ctp"); return true; } '; $unsetDebugKit = 'unset($this->components["DebugKit.Toolbar"]);'; $source = file_get_contents(LIBS . 'controller/controller.php'); $source = preg_replace('/^<\?php/', '', $source); $source = preg_replace('/\?>$/', '', $source); $source = preg_replace('/(function __construct\(.*\n)/', $cakeError . PHP_EOL . '$1' . $construct, $source); $source = preg_replace('/(function redirect\(.*\n)/', '$1' . $redirect, $source); $source = preg_replace('/(\$this->__mergeVars\(\);)/', '$1' . $unsetDebugKit, $source); eval($source);
[app/tests/views/redirect.ctp]
<?php echo json_encode($return);
[コントローラーのテスト内で]
<?php function testRedirect() { $result = $this->testAction('/users/view/1'); $josn = json_decode($result, true); $function = $josn !== null ? Set::extract('function', $josn) : null; if ($function === 'cakeError') { $result = Set::extract('method', $josn); } elseif ($function === 'redirect') { $result = Set::extract('url', $josn); } $this->assertEqual($result , '/users/login'); }