CakePHP で Ajax のテスト(CakeTestCase)を作ります。
前提
WebTestCase
WebTestCase では、fixture (テスト用のデータを準備する機能)が使えないので、
テストが面倒になるので、今回は使っていません。
WebTestCase で fixture 方法は、以下が参考になります。
- [2009/10/01] CakePHPのWebTestCaseでfixtureを使う
コントローラー
<?php class StatesController extends AppController { function ajax_edit($id = null) { // json で返すので、エラーを抑止 Configure::write('debug', 0); // json 用のレイアウトをセット // echo $content_for_layout; だけが記述されています。 $this->layout = 'ajax'; // Ajax のアクセスかどうか判定 // RequestHandler コンポーネントを使用 if (!$id || !$this->RequestHandler->isAjax()) { return $this->set('state', array('error' => true, 'message' => __('Invalid id or not XMLHttpRequest.', true))); } // data[<Model>][<param>] の形式でなければ、 $this->data の代わりに // $this->params['form'] で POST 内容を受け取れる if (empty($this->params['form'])) { return $this->set('state', array('error' => true, 'message' => __('The State could not be saved. Please, try again.', true))); } $data['State'] = $this->params['form']; $data['State']['id'] = $id; if (isset($data['State']['hex']) && strpos($data['State']['hex'], '#') === 0) { $data['State']['hex'] = substr($data['State']['hex'], 1); } if ($this->State->save($data, true, array('name', 'hex', 'type'))) { $this->set('state', array('error' => false, 'message' => __('The State has been saved', true))); } else { $this->set('state', array('error' => true, 'message' => __('The State could not be saved. Please, try again.', true))); } } }
テストケース
<?php class StatesControllerTestCase extends WhiskCakeTestCase { function testAjaxEdit() { $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'; $stateId = 1; $expect = $_POST = array( 'name' => 'changeName', 'hex' => 'ffffff', 'type' => '1', ); $this->_initControllerAction('ajax_edit', 'p/whisk/states/ajax_edit/' . $stateId, true); $this->States->ajax_edit($stateId); $this->assertFalse($this->States->redirectUrl); $this->assertFalse($this->States->statusCode); $output = $this->States->render('ajax_edit'); $this->assertFalse(json_decode($output)->error); $state = $this->States->State->findById($stateId); $this->assertEqual(array_intersect_key($state['State'], $expect), $expect); }
解説
<?php $_SERVER['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest';
ajax のリクエストかどうかを判定する「$this->RequestHandler->isAjax()」を true にします。
endTest で、 $_SERVER['HTTP_X_REQUESTED_WITH'] を unset しないと他のテストに影響します。
[cake/libs/controller/components/request_handler.php]
<?php class RequestHandlerComponent extends Object { /** * Returns true if the current HTTP request is Ajax, false otherwise * * @return boolean True if call is Ajax * @access public */ function isAjax() { // $_SERVER['HTTP_X_REQUESTED_WITH'] === "XMLHttpRequest" と同じです。 // env 関数は、basic.php で定義されています。 return env('HTTP_X_REQUESTED_WITH') === "XMLHttpRequest"; } }
<?php $expect = $_POST = array( 'name' => 'changeName', 'hex' => 'ffffff', 'type' => '1', );
XMLHttpRequest の送信するデータ形式が、
{name : 'name', hex : 'FF0033', type : '0'}
なら、
<?php $this->param['form'] = array( 'name' => 'name', 'hex' => 'FF0033', 'type' => '0' );
と格納されます。
$this->param['form'] には、 $_POST の値が格納されます。
また、
$this->data[
{data : {State: {name : 'name', hex : 'FF0033', type : '0'}}}
とすることで、
<?php $this->param['form'] = array( 'data' => array( 'State' => array( 'name' => 'name', 'hex' => 'FF0033', 'type' => '0' ) ) );
と格納されます。
特に、
$this->param['form']['data'] にあるものは、
$this->data に格納され、Cake 風のデータ形式になります。
<?php $this->data = array( 'State' => array( 'name' => 'name', 'hex' => 'FF0033', 'type' => '0' ) );
最後に、
この例では、$_POST に値をセットしているので、endTest で、 $_POST を unset しないと他のテストに影響します。