使用Zend Auth和Zend ACL进行PHP单元测试

时间:2010-07-28 11:38:29

标签: php unit-testing phpunit zend-auth zend-acl

我有一个登录后面的应用程序,并使用zend_acl和zend_auth。

在预分发期间,我有一个ACL插件,可以为ACL创建所有规则。我还有一个Auth插件,用于检查您是否已登录,如果可以,则根据ACL访问所请求的资源。

由于应用程序完全位于登录后面,因此只有在您登录时才会创建ACL。

单位测试这似乎是不可能的,或者更可能是我错过了一些明显的东西。

在我的单元测试设置方法中,我模拟了一个返回zend_auth实例的成功登录。通过的测试表明此登录成功。

但是,如果我然后通过测试尝试调度到另一个位置,或者评估登录用户是否有权访问给定资源,那么它总是被插件拒绝,因为它们仍然没有登录。我不确定为什么会这样,有人可以提出建议吗?

例如,这传递:

 public function testLoggedIn()
 {
  $this->assertTrue( Zend_Auth::getInstance()->hasIdentity() );
 }

这失败了,因为它被插件拒绝了:

 public function testUserAccess()
 {

   $this->dispatch('/home');
          $this->assertResponseCode(200);
          $this->assertQueryContentContains('#nav_side');  
          $this->resetRequest()
           ->resetResponse();

 }

这个,我发现似乎仍然会重定向回登录页面,因为插件不知道用户已登录。

任何帮助都非常感激。

2 个答案:

答案 0 :(得分:4)

这是在测试期间创建存根以替换ACL插件(或任何插件)的另一种方法。将它放在ControllerTestCase中并在测试用例setUp中调用它。

public function doLogin ()
{
    // create a fake identity
    $identity = new stdClass();
    $identity->Username = 'PHPUnit';
    Zend_Auth::getInstance()->getStorage()->write($identity);

    // remove the autoloaded plugin
    $front = Zend_Controller_Front::getInstance();
    $front->unregisterPlugin('My_Controller_Plugin_Acl');

    // create the stub for the Acl class
    $mockaAcl = $this->getMock(
      'My_Controller_Plugin_Acl',
      array('preDispatch'),
      array(),
      'My_Controller_Plugin_AclMock'
    ); 

    // register the stub acl plugin in its place
    $front->registerPlugin($mockAcl); 
}

这样就会调用您的存根preDispatch方法,这将绕过您的实际访问控制检查。

答案 1 :(得分:3)

您描述的问题在全局变量和OOP全局变量(Singleton模式)的使用中发生了很多。

PHPUnit的作者有一篇文章描述了如何通过使用依赖注入以及你已经获得的其他可能性来避免这种情况,因为它非常具有描述性,我建议你阅读它:) {{3} }

作为一个丑陋的替代方案(如果需要快速结果),您可以创建Zend_Auth的存根(在链接中描述)并使用PHP 5.3反射API将Zend_Auth实例变量设置为存根。

希望有所帮助(因为问题是4小时没有其他答案)