Hatena::ブログ(Diary)

いとうまさしのカチャカチャTODAY

2009-10-01

CakeTestCaseでtestActionを実行すると別のページにリダイレクトされちゃう問題

| 14:17

ControllerのテストをCakeTestCase#testActionで書こうと思ったのですが、

テストするactionの中でredirectのところを通ると本当にリダイレクトされてしまいます。

Google先生に聞いたところ、下記の記事が。

cakephp1.2でControllerをテストする際のredirectとcakeErrorアクションの取扱い

この記事ではrunkitという仕組みを使って、動的に定義を書き換えているようだけど、

今回は下記な感じで app ディレクトリ内だけで対応が済む感じにしてみました。

(1) app/webroot/test.php の 98行目付近に追記

require_once CAKE_TESTS_LIB . 'test_manager.php';

の後ろ辺りに

Configure::write('CAKE_ENV', 'test');

と定義。

(2) app/app_controller.php に下記を追記。

function redirect($url, $status = null, $exit = true) {
  // 「テスト実行時に本当にリダイレクトしちゃう」問題への対処
  if(Configure::read('CAKE_ENV') == 'test') {
    $this->set('function', 'redirect');
    $this->set('url', $url);
    $this->set('status', $status);
    $this->set('exit', $exit);
    $this->render(null, null, TESTS . DS . 'views' . DS . 'redirect.ctp');
  } else {
    parent::redirect($url, $status, $exit);
  }
}

(3) app/tests/views/redirect.ctp というファイルを下記の内容で作成。

<h2>redirect</h2>

<div>session flash : <?php $session->flash(); ?>

<?php if (isset($url) &&is_array($url)) : ?>

<?php foreach ($url as $k => $v) : ?>

<div>url : <?php echo '[', $k, '] : ', $v; ?></div>

<?php endforeach; ?>

<?php else: ?>

<div>url : <?php echo $url ? $url : ''; ?></div>

<?php endif; ?>

<div>status : <?php echo $status ? $status : ''; ?></div>

<div>exit : <?php echo $exit ? $exit : ''; ?></div>

以上の設定で、テスト実行中だけredirectの挙動を変えることができます。

テスト環境は別のDBを使う、という設定

| 13:35

テスト実行時はそれまで作ってたデータが消えてしまったりするのが嫌ですよね。

App::import('Model', 'User');
class UserTest extends User {
  $this->useDbConfig = 'test';
}  

とか定義して、このUserTestクラスをつかってUnitテストを書いたりしてみたんですが、

Userクラス内のhasManyとかbelongsToなどの関連データがtestじゃなくてdefaultの環境から

selectされちゃって行き詰まってしまいました。。。

runkitというやつで動的に定義をオーバーライドすることも考えましたが、

そこまですることでもないな、ということで対応は以下になりました。

app/webroot/test.php の 98行目付近

require_once CAKE_TESTS_LIB . 'test_manager.php';

の後ろ辺りに

Configure::write('CAKE_ENV', 'test');

と定義。

加えて app/app_models.php に下記のコンストラクタ定義を追加。

function __construct($id = false, $table = null, $ds = null) {
  if(Configure::read('CAKE_ENV')) $this->useDbConfig = Configure::read('CAKE_ENV');
  parent::__construct($id, $table, $ds);
}

Railsに比べ、サーバの構成とか、フォルダの構成とかが柔軟に変えられるのがCakePHPのいいところですね。

参考にした記事:

CakePHP 環境に応じてDBの設定を変える http://www.1x1.jp/blog/2006/09/cakephp_db_config.html

テスト環境でのDBの切り替え方 http://cakephp.blog16.jp/index.php/2008/07/02/p28