【问题标题】:Write unit test for a controller that uses AuthComponent in CakePHP 2在 CakePHP 2 中为使用 AuthComponent 的控制器编写单元测试
【发布时间】:2011-11-21 18:12:37
【问题描述】:

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

在这种情况下,我有一个夹具可以创建一个 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。由于我在操作中的比较中使用后者,它评估为假并导致 测试失败。

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

谢谢!

【问题讨论】:

    标签: php unit-testing cakephp authentication


    【解决方案1】:

    实际正确的答案应该是使用模拟对象而不是手动实际登录用户:

    $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 日更新

    你也可以 mock AuthComponent 的所有方法

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

    【讨论】:

    • 如果你必须使用generate(),那么使用ControllerTestCase有什么意义呢?
    • generate() 仅在 ControllerTestCase 中可用,提供它是为了使您的 testAction() 更容易,例如能够模拟控制器方法、组件、模型等。如果您不调用 generate () 你自己,然后 testAction() 将使用 CakePHP 默认值在内部为你完成(模拟 _stop() 和 redirect() 函数)
    • 我以为generate() 实际上做了其他事情。这就是为什么我一直在想,如果ControllerTestCase 为我提供了默认配置,为什么还要使用它。我会试试你的答案,让你知道:)
    • 无论如何,您有什么理由说明为什么手动登录用户不正确?我的意思是,我正在使用虚拟数据进行测试,应该没有任何风险......
    • 是的,节省时间!无论是编程时间还是执行时间,当您开始运行大量测试用例时进行模拟,对数据库的调用次数将很快减慢您的执行速度。在不需要时保持它们和最低限度是关键。此外,这不仅适用于 AuthComponent,还可以考虑任何其他组件,例如 Cookie 或 Security!您将如何伪造这两者的数据和环境?快速的答案总是模拟对象。
    【解决方案2】:

    我喜欢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 和可能的其他组件,这会使我对测试该特定方法的信心降低。尽管如此,我认为这是一个有效的用例,用于对控制器的不是动作的部分进行单元测试(例如“索引”、“视图”),但不能委托给组件,因为它们必须由核心框架调用.我仍在考虑如何抽象它以使其可用于任何控制器。

    【讨论】:

      【解决方案3】:

      代替:

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

      尝试以下方法之一:

      $this->Auth->data['User']['id']
      $this->Session->read('Auth.User.id')
      

      【讨论】:

      • 它也不起作用。这些方法不是等同的吗?
      【解决方案4】:

      这样设置:

      $this->Users->Session->write('Auth.User', 
          array('id' => 1,'and_other_fields_you_need' => 'whatever')
      );  
      

      【讨论】:

        【解决方案5】:

        Mark Story 给了我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);
        

        【讨论】:

          猜你喜欢
          • 2013-03-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-09-12
          • 2019-09-27
          • 1970-01-01
          • 2012-02-27
          相关资源
          最近更新 更多