我正在尝试测试允许编辑用户配置文件的控制器操作。除了我想测试的其他事情,每个登录的用户只能编辑自己的配置文件而不能编辑其他配置文件。如果违反此限制,操作必须重定向到预定义的主页。
在这种情况下,我有一个夹具,可以创建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'
(具有已记录用户的ID)是否显示该表单:
$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
。由于我在动作中进行比较时使用后者,因此将其评估为false并导致
测试失败。
奇怪的是,它在测试时发生,但在浏览器中执行操作时却没有。那么,测试这个动作的正确方法是什么?
谢谢!
答案 0 :(得分:5)
实际的正确答案应该是使用模拟对象而不是实际手动登录用户:
$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'));
使用模拟是测试控制器最简单的方法,也是最灵活的方法
2015年3月11日更新
您还可以模拟AuthComponent的所有方法
$this->controller = $this->generate('Users', array(
'components' => array('Auth') // Mock all Auth methods
));
答案 1 :(得分:1)
我喜欢Jose's answer,但是当遇到类似的情况时,我想使用实际的AuthComponent和Session来创建一个让我信心十足的测试。
我正在使用基于控制器的身份验证,这意味着我的应用中的每个控制器都必须提供自己的isAuthorized()回调。我想测试MyController :: isAuthorized()。使用模拟试验似乎太容易了。
因此,我没有使用TestCase :: generate()创建一个带有模拟组件的模拟控制器,而是按照Mark Story的优秀文章Testing CakePHP Controllers the hard way提供了我自己的模拟控制器,它使用真正的CakePHP登录用户AuthComponent。
这是my work。请参阅顶部附近的MockAnnouncementsController方法testIsAuthorized()和类def。
在我看来,CakePHP测试框架假设您只想通过requestAction()测试控制器。它的设计不是为了在控制器内对Controller :: isAuthorized()之类的回调实现进行直接单元测试,而不会模拟AuthComponent和其他组件,这会让我对该特定方法的测试缺乏信心。尽管如此,我认为这是一个有效的用例,用于对不是动作的控制器的部分进行单元测试(例如“index”,“view”),但不能委托给组件,因为它们必须由核心框架调用。我还在考虑如何抽象它以使其适用于任何控制器。
答案 2 :(得分:0)
而不是:
$this->Auth->user('id')
尝试以下方法之一:
$this->Auth->data['User']['id']
$this->Session->read('Auth.User.id')
答案 3 :(得分:0)
设置如下:
$this->Users->Session->write('Auth.User',
array('id' => 1,'and_other_fields_you_need' => 'whatever')
);
答案 4 :(得分:0)
马克故事给了我answer in a CakePHP ticket。基本上我必须像这样记录用户:
$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);