为在CakePHP 2中使用AuthComponent的控制器编写单元测试

eli*_*lon 5 php authentication unit-testing cakephp

我正在尝试测试允许编辑用户配置文件的控制器操作.除了我想测试的其他事情,每个登录的用户只能编辑自己的配置文件而不能编辑其他配置文件.如果违反此限制,操作必须重定向到预定义的主页.

在这种情况下,我有一个夹具,可以创建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'); 
Run Code Online (Sandbox Code Playgroud)

测试通过了这个断言.因此,下一步是检查执行'/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');
Run Code Online (Sandbox Code Playgroud)

但是这个断言失败了.在挖掘之后,debug()我发现它$this->Auth->user()返回了整个信息但$this->Auth->user('id')返回null.由于我在操作中的比较中使用后者,因此它的计算结果为false并导致测试失败.

奇怪的是,它是在测试时发生的,而不是在浏览器中执行操作时发生的.那么,测试这个动作的正确方法是什么?

谢谢!

Jos*_*uez 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')); 
Run Code Online (Sandbox Code Playgroud)

使用模拟是测试控制器最简单的方法,也是最灵活的方法

2015年3月11日更新

您还可以模拟AuthComponent的所有方法

$this->controller = $this->generate('Users', array(
    'components' => array('Auth') // Mock all Auth methods
));
Run Code Online (Sandbox Code Playgroud)

  • 是的,节省时间!无论是编程时间还是执行时间,当您开始运行大量测试用例时都会进行模拟,对数据库的调用次数将很快降低执行速度.保持它们并在不需要时保持最小是关键.此外,这不仅适用于AuthComponent,还可以考虑任何其他组件,如Cookie或安全性!你会如何假装这两个数据和环境?快速回答总是模拟对象. (2认同)