Написать модульный тест для контроллера, который использует AuthComponent в CakePHP 2 - PullRequest
5 голосов
/ 21 ноября 2011

Я пытаюсь проверить действие контроллера, которое позволяет редактировать профили пользователей. Среди прочего я хочу проверить, что каждый зарегистрированный пользователь может редактировать только свой профиль, а не другой. В случае нарушения этого ограничения действие должно быть перенаправлено на предварительно определенную домашнюю страницу.

В этом сценарии у меня есть прибор, который создает пользователя с ID = 1. Поэтому я думал о тестировании ограничения следующим образом:

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data); 
$this->testAction('/users/edit/2', array('method' => 'get')); 
$url = parse_url($this->headers['Location']); 
$this->assertEquals($url['path'], '/homepage'); 

Тест проходит это утверждение. Поэтому следующий шаг - проверить, показывает ли выполнение '/users/edit/1' с идентификатором зарегистрированного пользователя форму:

$this->testAction('/users/edit/1', array('method' => 'get', 'return' => 'vars'));
$matcher = array( 
  'tag' => 'form', 
  'ancestor' => array('tag' => 'div'), 
  'descendant' => array('tag' => 'fieldset'), 
); 
$this->assertTag($matcher, $this->vars['content_for_layout'], 'The edition form was not found');

Однако это утверждение не удается. После поиска с debug() я обнаружил, что $this->Auth->user() возвращает всю информацию, но $this->Auth->user('id') возвращает null. Поскольку я использую последнее в сравнении внутри действия, оно оценивается как ложное и вызывает тест не пройден.

Любопытно, что это происходит при тестировании, но не при выполнении действия в браузере. Итак, как правильно протестировать это действие?

Спасибо!

Ответы [ 5 ]

5 голосов
/ 24 ноября 2011

Для правильного ответа следует использовать фиктивные объекты, а не вводить пользователя вручную:

$this->controller = $this->generate('Users', array(
    'components' => array('Auth' => array('user')) //We mock the Auth Component here
));
$this->controller->Auth->staticExpects($this->once())->method('user') //The method user()
    ->with('id') //Will be called with first param 'id'
    ->will($this->returnValue(2)) //And will return something for me
$this->testAction('/users/edit/2', array('method' => 'get')); 

Использование mocks - самый простой способ тестирования контроллера, а также самый гибкий

Обновление от 11 марта 2015 года

Вы также можете смоделировать все методы AuthComponent

$this->controller = $this->generate('Users', array(
    'components' => array('Auth') // Mock all Auth methods
));
1 голос
/ 09 августа 2012

Мне нравится Ответ Хосе , но когда я сталкиваюсь с подобной ситуацией, я хочу использовать фактический AuthComponent и Session для создания теста, который придаст мне уверенности.

Я использую аутентификацию на основе контроллера, что означает, что каждый контроллер в моем приложении должен обеспечивать свой собственный обратный вызов isAuthorized () . Я хочу проверить MyController :: isAuthorized (). Кажется, что пройти тест с использованием насмешек слишком просто.

Итак, вместо того, чтобы использовать TestCase :: generate () для создания фиктивного контроллера с фиктивными компонентами, я последовал за превосходной статьей Марка Стори Тестирование контроллеров CakePHP трудным путем и предоставил свой собственный фиктивный контроллер, который входит в систему. пользователь с настоящим CakePHP AuthComponent.

Вот моя работа . См. Метод testIsAuthorized () и класс def для MockAnnouncementsController в верхней части.

Мне кажется, что среда тестирования CakePHP предполагает, что вы хотите тестировать контроллеры только через requestAction (). Он не был разработан для того, чтобы упростить непосредственное модульное тестирование реализаций обратного вызова, таких как Controller :: isAuthorized () внутри контроллера, без насмешек над AuthComponent и, возможно, другими компонентами, и это дало бы мне меньше уверенности в тестировании этого конкретного метода. Тем не менее, я думаю, что это действительный вариант использования для модульного тестирования частей контроллера, которые не являются действиями (например, «index», «view»), но не могут быть делегированы компоненту, потому что они должны вызываться базовой структурой , Я все еще думаю о том, как можно абстрагировать его, чтобы сделать его доступным для любого контроллера.

0 голосов
/ 22 ноября 2011

Установите это так:

$this->Users->Session->write('Auth.User', 
    array('id' => 1,'and_other_fields_you_need' => 'whatever')
);  
0 голосов
/ 24 ноября 2011

Марк Стори дает мне ответ в билете CakePHP .В основном я должен войти в систему пользователя, как это:

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data['User']);

вместо

$data = $this->Users->User->read(null, 1); 
$this->Users->Auth->login($data);
0 голосов
/ 22 ноября 2011

Вместо:

$this->Auth->user('id')

Попробуйте один из них:

$this->Auth->data['User']['id']
$this->Session->read('Auth.User.id')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...