Я пишу CakePHP Unit Test для одного из моих контроллеров. Контроллер имеет несколько вызовов метода AuthComponent::user()
для чтения данных текущего пользователя. Есть 3 варианта использования:
AuthComponent::user()
(без параметров, выборки всего массива) AuthComponent::user('id')
(выбирает идентификатор пользователя) AuthComponent::user('name')
(выбирает имя пользователя) Я пробовал два способа издеваться над AuthComponent в своем тесте:
// Mock the Controller and the Components $this->controller = $this->generate('Accounts', array( 'components' => array( 'Session', 'Auth' => array('user'), 'Acl' ) )); // Method 1, write the entire user array $this->controller->Auth->staticExpects($this->any())->method('user') ->will($this->returnValue(array( 'id' => 2, 'username' => 'admin', 'group_id' => 1 ))); // Method 2, specifically mock the AuthComponent::user('id') method $this->controller->Auth->staticExpects($this->any())->method('user') ->with('id') ->will($this->returnValue(2));
Однако эти методы не работают для меня. Метод 1 вообще не работает, операция сохранения в моем контроллере, которая использует текущий идентификатор пользователя, возвращает значение null, поэтому значение неправильно установлено / получено.
Метод 2, похоже, работает, но слишком широк, он также пытается привязать себя к вызову AuthComponent::user()
(без параметров), и он не работает с ошибкой:
Ошибка ожидания для имени метода равна при вызове ноль или более раз. Параметр 0 для вызова AuthComponent :: user (null) не соответствует ожидаемому значению. Не удалось утверждать, что null соответствует ожидаемому «id».
Как я могу получить правильные макеты для AuthComponent, чтобы можно было получить все поля / переменные?
Вот как я это делаю. Обратите внимание, что в этом коде я использую «Employee» в качестве модели пользователя, но ее легко изменить.
У меня есть суперкласс класса AppControllerTest.php, который возвращает обратный вызов для «пользовательского» метода. Обратный вызов обрабатывает случай с параметрами и без них. _generateMockWithAuthUserId
– это то, что вам нужно, но прочитайте все. Есть еще несколько вещей, заслуживающих внимания, как testPlaceholder. Вот мой класс:
<?php App::uses('Employee', 'Model'); /** * EmployeeNotesController Test Case * Holds common Fixture ID's and mocks for controllers */ class AppControllerTest extends ControllerTestCase { public $authUserId; public $authUser; /** * setUp method * * @return void */ public function setUp() { parent::setUp(); $this->Employee = ClassRegistry::init('Employee'); } /** * tearDown method * * @return void */ public function tearDown() { unset($this->Employee); parent::tearDown(); } public function testPlaceholder() { // This just here so we don't get "Failed - no tests found in class AppControllerTest" $this->assertTrue(true); } protected function _generateMockWithAuthUserId($contollerName, $employeeId) { $this->authUserId = $employeeId; $this->authUser = $this->Employee->findById($this->authUserId); $this->controller = $this->generate($contollerName, array( 'methods' => array( '_tryRememberMeLogin', '_checkSignUpProgress' ), 'components' => array( 'Auth' => array( 'user', 'loggedIn', ), 'Security' => array( '_validateCsrf', ), 'Session', ) )); $this->controller->Auth ->expects($this->any()) ->method('loggedIn') ->will($this->returnValue(true)); $this->controller->Auth ->staticExpects($this->any()) ->method('user') ->will($this->returnCallback(array($this, 'authUserCallback'))); } public function authUserCallback($param) { if (empty($param)) { return $this->authUser['Employee']; } else { return $this->authUser['Employee'][$param]; } } }
с<?php App::uses('Employee', 'Model'); /** * EmployeeNotesController Test Case * Holds common Fixture ID's and mocks for controllers */ class AppControllerTest extends ControllerTestCase { public $authUserId; public $authUser; /** * setUp method * * @return void */ public function setUp() { parent::setUp(); $this->Employee = ClassRegistry::init('Employee'); } /** * tearDown method * * @return void */ public function tearDown() { unset($this->Employee); parent::tearDown(); } public function testPlaceholder() { // This just here so we don't get "Failed - no tests found in class AppControllerTest" $this->assertTrue(true); } protected function _generateMockWithAuthUserId($contollerName, $employeeId) { $this->authUserId = $employeeId; $this->authUser = $this->Employee->findById($this->authUserId); $this->controller = $this->generate($contollerName, array( 'methods' => array( '_tryRememberMeLogin', '_checkSignUpProgress' ), 'components' => array( 'Auth' => array( 'user', 'loggedIn', ), 'Security' => array( '_validateCsrf', ), 'Session', ) )); $this->controller->Auth ->expects($this->any()) ->method('loggedIn') ->will($this->returnValue(true)); $this->controller->Auth ->staticExpects($this->any()) ->method('user') ->will($this->returnCallback(array($this, 'authUserCallback'))); } public function authUserCallback($param) { if (empty($param)) { return $this->authUser['Employee']; } else { return $this->authUser['Employee'][$param]; } } }
Затем мои тестовые примеры контроллера наследуются от этого класса:
require_once dirname(__FILE__) . DS . 'AppControllerTest.php'; class EmployeeNotesControllerTestCase extends AppControllerTest { // Tests go here
И когда вы хотите издеваться над компонентом auth в тесте, вы вызываете
$this->_generateMockWithAuthUserId('EmployeeNotes', $authUserId);
Где «EmployeeNotes» будет именем вашего контроллера и $ authUserId идентификатором пользователя в тестовой базе данных.