CakePHP1.3 コントローラーのテスト(testAction なし バージョン)
コントローラーのテストを testAction メソッドを使わず書いた場合の例です。
前提 & 環境
素材
- bake で作成したものに手を加えています。
- Auth コンポーネントのパスワードハッシュ化回避をしています。
- Auth コンポーネント は、AppController で設定しています。
<?php class UsersController extends AppController { var $name = 'Users'; function beforeFilter() { $this->Auth->allow('add'); // not auth action $action = Set::extract($this->params, 'action'); // no hash passowrd action if (in_array($action, array('add', 'edit'), true)) { $this->Auth->authenticate = ClassRegistry::init('User'); } } function login() { // Processing is handovered to Auth component. } function logout() { $this->Session->setFlash('logout'); $this->Auth->logout(); $this->redirect(array('action' => 'index')); } function index() { $this->User->recursive = 0; $this->set('users', $this->paginate()); } function view($id = null) { if (!$id) { $this->Session->setFlash(__('Invalid User', true)); $this->redirect(array('action' => 'index')); } $this->set('user', $this->User->read(null, $id)); } function add() { if (!empty($this->data)) { $this->User->create($this->data); if ($this->User->validates()) { $path = $this->Auth->getModel()->alias . '.' . $this->Auth->fields['password']; $this->data = Set::insert($this->data, $path, $this->Auth->password(Set::extract($this->data, $path))); if ($this->User->save($this->data, false)) { $this->Session->setFlash(__('The User has been saved', true)); $this->redirect(array('action' => 'index')); } } $this->Session->setFlash(__('The User could not be saved. Please, try again.', true)); } } function edit($id = null) { if ((!$id && empty($this->data)) || !$id) { $this->Session->setFlash(__('Invalid User', true)); $this->redirect(array('action' => 'index')); } if (!empty($this->data)) { $this->User->create($this->data); if ($this->User->validates()) { $path = $this->Auth->getModel()->alias . '.' . $this->Auth->fields['password']; $this->data = Set::insert($this->data, $path, $this->Auth->password(Set::extract($this->data, $path))); if ($this->User->save($this->data, false)) { $this->Session->setFlash(__('The User has been saved', true)); $this->redirect(array('action' => 'index')); } } $this->Session->setFlash(__('The User could not be saved. Please, try again.', true)); } if (empty($this->data)) { $this->data = $this->User->read(null, $id); } } function delete($id = null) { if (!$id) { $this->Session->setFlash(__('Invalid id for User', true)); $this->redirect(array('action' => 'index')); } if ($this->User->delete($id)) { $this->Session->setFlash(__('User deleted', true)); $this->redirect(array('action' => 'index')); } $this->Session->setFlash(__('The User could not be deleted. Please, try again.', true)); $this->redirect(array('action' => 'index')); } }
パスワードは、「aaaa」です。
<?php class UserFixture extends CakeTestFixture { var $name = 'User'; var $fields = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'), 'created' => array('type' => 'datetime', 'null' => true, 'default' => NULL), 'modified' => array('type' => 'datetime', 'null' => true, 'default' => NULL), 'username' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 200), 'password' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 200), 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1)), 'tableParameters' => array('charset' => 'utf8', 'collate' => 'utf8_unicode_ci', 'engine' => 'InnoDB') ); var $records = array( array( 'id' => 1, 'created' => '2010-01-01 00:00:00', 'modified' => '2010-01-01 00:00:00', 'username' => 'aaaa', 'password' => '886cda4198f50ec0167c8eb38edf7036c838c3aa' ), ); }
- CakeTestCase を拡張して、共通処理を追加しました。
- コントローラーやコンポーネントの初期化などについては、下記の「おさらい」を参照
<?php App::import(null, 'CakeTestCase', false, CAKE_TESTS_LIB); class WhiskCakeTestCase extends CakeTestCase { // 対象のコントローラー名 /** * @var AppController */ public $name; // 対象のコントローラーインスタンス protected $_this; // startup メソッドで作成するコントローラーインスタンスを作成します。 protected function _createControllerInstance(&$_this) { $this->_this = $_this; $this->name = $name = str_replace('ControllerTestCase', '', get_class($_this)); $controllerName = 'Test' . $name . 'Controller'; // コントローラーインスタンスを作成します。 $_this->$name =& new $controllerName; // モデルを読み込みとコンポーネントの読み込みを行います。 $_this->$name->constructClasses(); // params プロパティは、本来 Dispatcher クラスで設定されるため、手動で設定します。 // また、 // Auth コンポーネント でも必要になります。 $_this->$name->params['controller'] = strtolower($name); $_this->$name->params['pass'] = array(); $_this->$name->params['named'] = array(); } // 各アクションで必要な初期値をセットします。 protected function _initControllerAction($action = 'index', $url = '/', $login = false) { $this->_this->{$this->name}->params['action'] = $action; $this->_this->{$this->name}->params['url']['url'] = $url; // $_SESSION['Auth']['User'] に値があれば、認証していることになります。 // Auth->user() は、$_SESSION['Auth']['User'] をチェックします。 if ($login) { $this->_this->{$this->name}->Session->write('Auth.User', array( 'id' => 1, 'username' => 'admin', )); } // ・コンポーネントの初期化(Component::initialize)、 // ・controller::beforeFilter の実行、 // ・コンポーネントの実行($this->Component->triggerCallback('startup', $this)) // を行います。 $this->_this->{$this->name}->startupProcess(); } function endTest() { // ログアウト $this->_this->{$this->name}->Auth->logout(); // セッションを空にする unset($_SESSION); // コントローラーインスタンスを削除 unset($this->_this->{$this->name}); // 登録したクラスをすべて削除する ClassRegistry::flush(); } }
bake で作成したものに手を加えて作成しました。
<?php App::import('Controller', 'Users'); // コントローラークラスを継承したテスト用のコントローラークラスを作成します。 // Render の抑制や、実際にリダイレクトをしては困るので、 // 処理を書き換えています。 class TestUsersController extends UsersController { public $autoRender = false; public $redirectUrl = false; public function redirect($url, $status = null, $exit = true) { return $this->redirectUrl = $url; } } class UsersControllerTestCase extends WhiskCakeTestCase { // このコメント部分はなくとも大丈夫です。 // Eclipse の補完用です。 /** * controller * * @var TestUsersController */ var $Users; var $fixtures = array('app.user'); // test*** のメソッドを実行する前に呼ばれます。 // コントローラーのインスタンスを作成します。 function startTest() { $this->_createControllerInstance($this); } // なくてもOK function endTest() { parent::endTest(); } function testNologin() { // ログインが不要なのは、add アクションのみ // コントローラーアクションの初期化 $this->_initControllerAction('index', 'users', false); // Auth コンポーネントでリダイレクトがあれば、 // $this->Users->redirectUrl に 「/users/login」がセットされるはず $this->assertEqual($this->Users->redirectUrl, '/users/login'); // $this->Users->redirectUrl を初期化 $this->Users->redirectUrl = false; $this->_initControllerAction('add', 'users/add', false); // add アクションはログイン不要のため、「false」を期待 $this->assertFalse($this->Users->redirectUrl); $this->Users->redirectUrl = false; $this->_initControllerAction('edit', 'users/edit/1', false); $this->assertEqual($this->Users->redirectUrl, '/users/login'); $this->Users->redirectUrl = false; $this->_initControllerAction('view', 'users/view/1', false); $this->assertEqual($this->Users->redirectUrl, '/users/login'); $this->Users->redirectUrl = false; $this->_initControllerAction('delete', 'users/delete/1', false); $this->assertEqual($this->Users->redirectUrl, '/users/login'); } function testLogin() { $this->Users->data = array('User' => array( 'username' => 'aaaa', 'password' => 'aaaa' )); $this->_initControllerAction('login', 'users/login', false); $this->assertEqual($this->Users->redirectUrl, '/'); $this->assertNotEqual($this->Users->Auth->user(), null); } function testLogout() { $this->_initControllerAction('logout', 'users/logout', true); $this->assertNotEqual($this->Users->Auth->user(), null); $this->Users->logout(); $this->assertNull($this->Users->Auth->user()); $this->assertEqual($this->Users->redirectUrl, array('action' => 'index')); } function testIndex() { // 第三引数 true : $this->Users->Auth->user() を成功させる $this->_initControllerAction('index', 'users', true); $this->assertFalse($this->Users->redirectUrl); $this->assertNotEqual($this->Users->Auth->user(), null); $this->Users->index(); $output = $this->Users->render('index'); $this->assertFalse(strpos($output, '<pre class="cake-debug">')); } function testAdd() { $this->_initControllerAction('add', 'users/add', true); $beforeCount = $this->Users->User->find('count'); $this->assertEqual(1, $beforeCount); $this->Users->data = array('User' => array( 'username' => 'bbbb', 'password' => 'cccc' )); $this->Users->add(); $this->assertEqual($this->Users->redirectUrl, array('action' => 'index')); $afterCount = $this->Users->User->find('count'); $this->assertEqual($beforeCount + 1, $afterCount); $user = $this->Users->User->findById($afterCount); $expect = array( 'username' => $this->Users->data['User']['username'], 'password' => $this->Users->Auth->hashPasswords($this->Users->data['User']['password']), ); $this->assertEqual(array_intersect_key($user['User'], $expect), $expect); } function testDelete() { $this->_initControllerAction('delete', 'users/delete/1', true); $beforeCount = $this->Users->User->find('count'); $this->Users->delete(1); $this->assertEqual($this->Users->redirectUrl, array('action' => 'index')); $afterCount = $this->Users->User->find('count'); $this->assertEqual($beforeCount - 1, $afterCount); $this->assertEqual(false, $this->Users->User->findById(1)); } function testEdit() { $this->_initControllerAction('edit', 'users/edit/1', true); $this->Users->data = array('User' => array( 'id' => '1', 'username' => 'modified', 'password' => 'modified' )); $this->Users->edit(1); $this->assertEqual($this->Users->redirectUrl, array('action' => 'index')); $user = $this->Users->User->findById(1); $expect = array( 'username' => $this->Users->data['User']['username'], 'password' => $this->Users->Auth->hashPasswords($this->Users->data['User']['password']), ); $this->assertEqual(array_intersect_key($user['User'], $expect), $expect); } }