2013-02-10 122 views
23

我是学习单元测试,我试图解决了以下问题:ZF2单元测试认证

Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for zfcUserAuthentication 

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

Simple ZF2 Unit Tests for a controller using ZfcUser

所以我的setUp函数看起来一样。不幸的是,我得到错误信息:

Zend\Mvc\Exception\InvalidPluginException: Plugin of type Mock_ZfcUserAuthentication_868bf824 is invalid; must implement Zend\Mvc\Controller\Plugin\PluginInterface 

它的代码(在我的代码拆分以同样的方式),这部分造成的:

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

的$ authMock对象显然不是实现plugininterface,我需要实现以传入setService。

$ authMock不是意味着在那里传递,因为它用于单元测试吗?我应该使用不同的(面向单元测试)setService方法吗?

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

感谢您的任何建议。

===编辑(2013年11月2日)===

我希望把重点放在这一部分澄清,因为我认为这就是问题所在区域:

// 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); 

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

+0

我纠正它不是必要的单元测试控制器,因为它是模型?我发现那是我保存我所有的验证码的地方。 – Shoreline 2013-04-04 16:06:49

+0

我最近做了类似的事,没有任何问题。你的完整的测试用例类是什么样的?你的测试引导是什么样的?最后是你要测试的动作。 – Ruben 2013-06-01 01:58:41

+0

单元测试时是否使用特殊的应用程序配置?在这种情况下,zfcUser模块可能不会在测试环境中加载。 – SmasherHell 2013-11-07 14:49:00

回答

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' 
     ); 

所以,如果没有类或接口,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); 
0

我刚才为FlashMessenger插件做了一个例子。您应该只使用ControllerPluginManager来覆盖ControllerPlugin。确保您的应用程序引导程序调用 setApplicationConfig();

<?php 
namespace SimpleTest\Controller; 

use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase; 

class SimpleControllerTest extends AbstractHttpControllerTestCase { 

    public function testControllerWillAddErrorMessageToFlashMessenger() 
    { 
     $flashMessengerMock = $this->getMockBuilder('\Zend\Mvc\Controller\Plugin\FlashMessenger', array('addErrorMessage'))->getMock(); 
     $flashMessengerMock->expects($this->once()) 
      ->method('addErrorMessage') 
      ->will($this->returnValue(array())); 


     $serviceManager = $this->getApplicationServiceLocator(); 
     $serviceManager->setAllowOverride(true); 
     $serviceManager->get('ControllerPluginManager')->setService('flashMessenger', $flashMessengerMock); 

     $this->dispatch('/error/message'); 

    } 
}?>