cakephp testActionでredirectするアクションをテストする方法

 2009/05/25
このエントリーをはてなブックマークに追加

まだ色々試行錯誤中なんだけど、途中経過としてメモ。

cakephpでSimpleTestを使ったテスト自動化をしているんだけど、コントローラーのテストでは、メソッドにredirectが含まれていると、テストが途中で中断してしまう。(テスト自体がリダイレクトされてしまう)。

絵で説明すると、最初にSImpleTestにアクセスすると、以下のような画面が表示される。これは特に問題ない。

caketest12

んで、メソッドの中にredirectが含まれないやつのテスト結果。これも緑なのでOK。

caketest31

じゃあ、ということで、以下のメソッドについてテストを書く。

function login(){
	if ($this->Auth->user())
	{
		if (!empty($this->data))
		{
			$this->log("ログインしました", LOG_DEBUG);
			$this->User->updateLoginInfo($this->Auth->user('id'));
			$this->redirect($this->Auth->redirect());
		}
		else
		{
			$this->redirect(array('action' => 'index'));
		}
	}
	else
	{
		if (!empty($this->data))
		{
			$this->Session->setFlash($this->Auth->loginError);
		}
	}
}

もう、ふんだんにredirectしちゃってる。まぁloginだから普通なんだけど。 んで、テスト内容的には

  • ログイン完了してたら、「ようこそ××さん」があるはず
  • GETでアクセスしたら、ログイン画面があるはず
  • 誤ったPOSTデータが来たら、ログインエラーのメッセージがあるはず
とかそんな感じになるかと思うのだが、これ、そのままだとテスト出来ない。 例えば、ログインのテストコードは以下のように書いてみる。
$data = array(
	"User" => array(
		"username" => "foo",
		"password" => "bar",
	),
);
$result = $this->testAction('/users/login', array(
	'data' => $data,
	'fixturize' => true,
	'method' => 'post',
	'return' => 'contents')
);

これは正常ログインするケースなのだが、正しい動作なら、/usrs/loginで正常に認証を完了すると、ログイン後トップページにリダイレクトされて、「ようこそ××さん」とかが出るはず。なので、戻り値の$resultを正規表現でごにょごにょすれば完成のように見えるんだけど、このテストを実行すると、下図のようになる。

caketest22

残念ながら、テスト対象クラスの中のredirect関数で、本当にredirectされちまった。。。

ということで、対応方法を色々考えたのだが、一番手っ取り早い方法を書いておく。それは

runkit(PHPの拡張) を使う。runkitは

runkitは、PHPの定数や関数、クラス、メソッドを追加・変更・削除したり、独自のスーパーグローバル変数を定義したりできるPHPのエクステンションです。
http://www.phppro.jp/phptips/archives/vol50/1より) ということで、今ある関数やクラスの挙動を外部から動的に変更できるすぐれものだ。

こいつを使って、例えばこうする。

function setUp() {
	$this->Commodity =& ClassRegistry::init('Commodity');
	$this->User =& ClassRegistry::init('User');
	$this->User->useDbConfig = "test_suite";

	//redirectメソッドを抹消
	runkit_method_redefine("UsersController" , "redirect"  , '$url, $status = null, $exit = true'  , "return true;" );
	$this->Users = new TestUsers();
	$this->Users->constructClasses();
}

これで、UsersControllerのredirectメソッドは単にtrueを返すように挙動が変更され、テストが途中で中断されることもなくなった。 あくまでテストコードなので、これで十分だと思うのだが、どうだろうか? もっと良い方法があればコメントで教えてほしいなぁと。

 2009/05/25
このエントリーをはてなブックマークに追加

サイト内検索


著作

寄稿

Latest post: