Php Zend Framework 2条令2模块-控制器单元测试中无服务定位器
这是我的情况。我正在开发Zend Framework 2应用程序。我正在使用Doctrine模块与MySQL数据库通信。它在应用程序中运行良好,我可以从控制器内的服务定位器加载实体管理器 但是在我的控制器单元测试中,服务定位器不存在,因此所有处理数据库的测试都失败,错误消息如下:Php Zend Framework 2条令2模块-控制器单元测试中无服务定位器,php,doctrine-orm,phpunit,zend-framework2,Php,Doctrine Orm,Phpunit,Zend Framework2,这是我的情况。我正在开发Zend Framework 2应用程序。我正在使用Doctrine模块与MySQL数据库通信。它在应用程序中运行良好,我可以从控制器内的服务定位器加载实体管理器 但是在我的控制器单元测试中,服务定位器不存在,因此所有处理数据库的测试都失败,错误消息如下: chdir('/path/to/application/root'); // if you're using composer to install zf2 include_once 'vendor/autoload
chdir('/path/to/application/root');
// if you're using composer to install zf2
include_once 'vendor/autoload.php';
// if not using composer initialize your custom autoloading here
$configuration = include('config/application.config.php');
$serviceManager = new ServiceManager(new ServiceManagerConfig(
isset($configuration['service_manager']) ? $configuration['service_manager'] : array()
));
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->setFactory('ServiceListener', 'Zend\Mvc\Service\ServiceListenerFactory');
$moduleManager = $serviceManager->get('ModuleManager');
$moduleManager->loadModules();
$serviceManager->setAllowOverride(true);
$application = $serviceManager->get('Application');
$event = new MvcEvent();
$event->setTarget($application);
$event->setApplication($application)
->setRequest($application->getRequest())
->setResponse($application->getResponse())
->setRouter($serviceManager->get('Router'));
致命错误:对第19行/Users/richardknop/Projects/myproject/module/Api/src/Api/Controller/UserController.php中的非对象调用成员函数get()
我已将问题缩小到以下方法:
$this->getServiceLocator()
它在我的控制器中工作,但在单元测试中返回NULL
这是我的application.config.php:
<?php
return array(
'modules' => array(
'DoctrineModule',
'DoctrineORMModule',
'Api',
),
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'./module',
'./vendor',
),
),
);
在我的控制器中,我使用以下方法获取实体管理器:
private $_em;
private function _getEntityManager()
{
if (null === $this->_em) {
$this->_em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->_em;
}
现在我的单元测试。以下是引导文件:
<?php
chdir(dirname(__DIR__));
include __DIR__ . '/../init_autoloader.php';
return Zend\Mvc\Application::init(include 'config/application.config.php');
控制器单元测试示例如下所示:
public function setUp()
{
$this->_controller = new UserTokenController;
$this->_request = new Request;
$this->_routeMatch = new RouteMatch(array('controller' => 'user'));
$this->_event = new MvcEvent();
$this->_event->setRouteMatch($this->_routeMatch);
$this->_controller->setEvent($this->_event);
}
public function testGetListHttpStatusCode()
{
$response = $this->_controller->dispatch($this->_request);
$this->assertEquals(405, $response->getStatusCode());
}
所有未连接到数据库的测试均通过。使用实体管理器的测试失败,但出现以下错误:
致命错误:对第19行/Users/richardknop/Projects/myproject/module/Api/src/Api/Controller/UserController.php中的非对象调用成员函数get()
这是第19行:
$this->_em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
它失败的原因是$this->getServiceLocator()
返回NULL
有什么办法解决这个问题吗?不要在bootstrap.php中这样做
return Zend\Mvc\Application::init(include 'config/application.config.php');` in your
但是像这样的事情:
chdir('/path/to/application/root');
// if you're using composer to install zf2
include_once 'vendor/autoload.php';
// if not using composer initialize your custom autoloading here
$configuration = include('config/application.config.php');
$serviceManager = new ServiceManager(new ServiceManagerConfig(
isset($configuration['service_manager']) ? $configuration['service_manager'] : array()
));
$serviceManager->setService('ApplicationConfig', $configuration);
$serviceManager->setFactory('ServiceListener', 'Zend\Mvc\Service\ServiceListenerFactory');
$moduleManager = $serviceManager->get('ModuleManager');
$moduleManager->loadModules();
$serviceManager->setAllowOverride(true);
$application = $serviceManager->get('Application');
$event = new MvcEvent();
$event->setTarget($application);
$event->setApplication($application)
->setRequest($application->getRequest())
->setResponse($application->getResponse())
->setRouter($serviceManager->get('Router'));
然后,您可以在测试用例中创建静态方法来设置和获取事件
namespace My;
class TestCase extends \Some\Basic\TestCase
{
protected static $_mvcEvent;
public static function setMvcEvent(MvcEvent $e) {
self::$_mvcEvent = $e;
}
public static function getMvcEvent() {
return self::$_mvcEvent;
}
}
…并从bootstrap.php文件中注入它
My\TestCase::setMvcEvent($event);
在测试的设置方法中,只需这样做
$this->_controller = new UserTokenController;
$this->_controller->setEvent(self::getMvcEvent());
$this->_controller->setServiceLocator(
self::getMvcEvent()->getApplication()->getServiceManager()
);
还将来自事件->应用程序的请求等注入控制器…只需从 \Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase 它是init服务定位器,并执行许多其他控制器的工作。以及成为可用的控制器断言、响应断言、CSS断言等。
示例的细节在这里查看毕竟我使用了一种稍微不同的方法(但主要思想是相同的,我只是在Bootstrap.php for phpunit中添加了更多的逻辑)。但是你的也可以。我的也做了很多,只是把它简化为基本要求。我也在使用ZF2+Doctrine2,并遵循您的方法。设置ServiceLocator时,事件似乎没有传播到控制器插件——例如,路由器是在ServiceLocator中设置的,而不是在redirect()插件中设置的。有没有关于如何设置的想法?
$this->_controller = new UserTokenController;
$this->_controller->setEvent(self::getMvcEvent());
$this->_controller->setServiceLocator(
self::getMvcEvent()->getApplication()->getServiceManager()
);