ZF2单元测试认证

Sho*_*ine 23 phpunit zend-framework2 zfcuser

我正在学习单元测试,我试图解决以下问题:

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for zfcUserAuthentication
Run Code Online (Sandbox Code Playgroud)

...使用给出的唯一答案:

简单的ZF2单元使用ZfcUser测试控制器

所以我的setUp函数看起来一样.不幸的是,我收到错误消息:

Zend\Mvc\Exception\InvalidPluginException: Plugin of type Mock_ZfcUserAuthentication_868bf824 is invalid; must implement Zend\Mvc\Controller\Plugin\PluginInterface
Run Code Online (Sandbox Code Playgroud)

它是由代码的这一部分引起的(在我的代码中以相同的方式分开):

$this -> controller->getPluginManager()
->setService('zfcUserAuthentication', $authMock); // Error refers to this line.
Run Code Online (Sandbox Code Playgroud)

$ authMock对象显然没有实现plugininterface,我需要实现它来传递到setService.

$ authMock是不是要通过那里,因为它用于单元测试?我应该使用不同的(面向单元测试的)setService方法吗?

我需要一种方法来处理登录到我的应用程序,或者我的单元测试毫无意义.

谢谢你的建议.

===编辑(11/02/2013)===

我想专注于这一部分以澄清,因为我认为这是问题领域:

// Getting mock of authentication object, which is used as a plugin.
$authMock = $this->getMock('ZfcUser\Controller\Plugin\ZfcUserAuthentication');

// Some expectations of the authentication service.
$authMock   -> expects($this->any())
    -> method('hasIdentity')
    -> will($this->returnValue(true));  

$authMock   -> expects($this->any())
    -> method('getIdentity')
    -> will($this->returnValue($ZfcUserMock));

// At this point, PluginManager disallows mock being assigned as plugin because 
// it will not implement plugin interface, as mentioned.
$this -> controller->getPluginManager()
->setService('zfcUserAuthentication', $authMock);
Run Code Online (Sandbox Code Playgroud)

如果模拟不处理必要的实现,我还要假装登录?

Sch*_*eis 3

您的名称空间或自动加载器有问题。

当您创建模拟时,ZfcUser\Controller\Plugin\ZfcUserAuthentication找不到 的类定义。因此 PHPUnit 创建一个模拟,仅为您的测试扩展此类。如果该类可用,那么 PHPUnit 将在进行模拟时使用实际的类进行扩展,然后模拟将使用父类/接口。

您可以在这里看到这个逻辑:https://github.com/sebastianbergmann/phpunit-mock-objects/blob/master/PHPUnit/Framework/MockObject/Generator.php

    if (!class_exists($mockClassName['fullClassName'], $callAutoload) &&
        !interface_exists($mockClassName['fullClassName'], $callAutoload)) {
        $prologue = 'class ' . $mockClassName['originalClassName'] . "\n{\n}\n\n";

        if (!empty($mockClassName['namespaceName'])) {
            $prologue = 'namespace ' . $mockClassName['namespaceName'] .
                        " {\n\n" . $prologue . "}\n\n" .
                        "namespace {\n\n";

            $epilogue = "\n\n}";
        }

        $cloneTemplate = new Text_Template(
          $templateDir . 'mocked_clone.tpl'
        );
Run Code Online (Sandbox Code Playgroud)

因此,如果没有类或接口,PHPUnit 实际上会自己创建一个类或接口,以便模拟能够满足原始类名的类型提示。但是,任何父类或接口都不会被包含在内,因为 PHPUnit 不知道它们。

这可能是由于您的测试中未包含正确的命名空间或自动加载器存在问题。如果没有实际看到整个测试文件,很难判断。


或者,您可以在测试中ZfcUser\Controller\Plugin\ZfcUserAuthentication模拟并将其传递到插件管理器中,而不是模拟 。Zend\Mvc\Controller\Plugin\PluginInterface尽管如果您在代码中对插件进行类型提示,您的测试仍然无法工作。

//Mock the plugin interface for checking authorization
$authMock = $this->getMock('Zend\Mvc\Controller\Plugin\PluginInterface');

// Some expectations of the authentication service.
$authMock   -> expects($this->any())
    -> method('hasIdentity')
    -> will($this->returnValue(true));  

$authMock   -> expects($this->any())
    -> method('getIdentity')
    -> will($this->returnValue($ZfcUserMock));

$this -> controller->getPluginManager()
->setService('zfcUserAuthentication', $authMock);
Run Code Online (Sandbox Code Playgroud)