I am trying to test a controller action that allows edition of user profiles. Among other things I want to test that every logged user can only edit its own profile and not other's. In case of breaking this restriction the action must redirect to a predefined home page.
With this scenario, I have a fixture that creates a user with ID = 1. So I was thinking on testing the restriction this way:
$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');
The test passes this assert. So the next step is to check if executing '/users/edit/1'
, which has the ID of the logged user, shows the form:
$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');
However this assert fails. After digging around with debug()
I've found that $this->Auth->user()
returns the whole information but $this->Auth->user('id')
returns null
. Since I use the latter in a comparison within the action, it evaluates as false and causes the
test to fail.
The curious thing is that it happens when testing but not when executing the action in a browser. So, what's the correct way of testing this action?
Thanks!
The actual correct answer should be using mock objects instead of actually login the user in manually:
$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'));
Using mocks is the most easy way to test a controller, and also the most flexible one
Update 11 March 2015
You can also mock all method of AuthComponent
$this->controller = $this->generate('Users', array(
'components' => array('Auth') // Mock all Auth methods
));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With