我需要测试一个用 ZF2 编写的大型站点。有 443 个测试和大约 10000 个断言。代码覆盖率测试需要 6 个小时! 我想我发现了问题:在 Controller 的测试中,我使用了 AbstractHttpControllerTestCase 中的调度方法。 dispatch 方法的执行时间在每次测试后都在增加(从几分之一秒到几十秒)。
我使用 ZF 2.1.3、PHPUnit 3.7、PHP_CodeCoverage 1.2、Xdebug v2.2.1、PHP 5.4.7。
我的派发方式:
public function dispatch($url, $method = HttpRequest::METHOD_GET, $params = array())
{
$s = microtime(true);
parent::dispatch($url, $method, $params);
$end = microtime(true) - $s;
echo 'dis: '.$end."\n";
return $this->getApplication()->getMvcEvent()->getResult();
}
parent::dispatch 是来自 AbstractHttpControllerTestCase 的方法。
测试样本:
$result = $this->dispatch('/archive/finance/older');
$this->assertControllerName('skycontent\controller\article');
$this->assertActionName('archive');
$this->assertParamValue('older', true);
$this->assertParamValue('category', 'finance');
$vars = (array) $result->getVariables();
$this->assertArrayHasKey('archivePosts', $vars);
请帮忙。 谢谢。
更新:
我使用进程隔离并在大约 15 分钟内完成了测试(没有代码覆盖率),但我在测试中遇到了标记为已跳过的错误:
PHPUnit_Framework_Exception: PHP Fatal error: Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in -:44
最佳答案
Zend\ServiceManager
和 Zend\EventManager
都大量使用了 closures .您不能序列化整个应用程序实例并期望它能正常工作,因为这基本上意味着您尝试序列化定义为闭包的服务工厂和事件监听器。
解决方案可能是使用像the one of DoctrineORMModule 这样的测试Bootstrap.php
,它不会在内存中保留应用程序实例。
这是一个简化的示例:
require_once __DIR__ . '/../vendor/autoload.php';
$appConfig = require __DIR__ . '/TestConfiguration.php';
\YourModuleTest\Util\ServiceManagerFactory::setConfig($appConfig);
unset($appConfig);
(TestConfiguration
应该看起来像 standard mvc application's config )
您还需要 ServiceManagerFactory
。可以找到示例实现 here和 here .
namespace YourModuleTest\Util;
class ServiceManagerFactory
{
/**
* @var array
*/
protected static $config;
/**
* @param array $config
*/
public static function setConfig(array $config)
{
static::$config = $config;
}
/**
* Builds a new service manager
* Emulates {@see \Zend\Mvc\Application::init()}
*/
public static function getServiceManager()
{
$serviceManager = new ServiceManager(new ServiceManagerConfig(
isset(static::$config['service_manager'])
? static::$config['service_manager']
: array()
));
$serviceManager->setService('ApplicationConfig', static::$config);
$serviceManager->setFactory(
'ServiceListener',
'Zend\Mvc\Service\ServiceListenerFactory'
);
/** @var $moduleManager \Zend\ModuleManager\ModuleManager */
$moduleManager = $serviceManager->get('ModuleManager');
$moduleManager->loadModules();
return $serviceManager;
}
}
现在,无论您想在测试中的什么地方,您都可以:
$serviceManager = \YourModuleTest\Util\ServiceManagerFactory::getServiceManager();
$application = $serviceManager->get('Application');
$application->bootstrap();
// ...
使用此设置,您可以在绝缘中运行测试。
另一方面,您应该首先关注真正的单元测试,因为 ZF2 确实简化了您编写复杂对象的方式。您还应该正确设置覆盖过滤器,以便不处理不相关的代码(这可能会占用很多时间)。
此外,重用 mvc 应用程序实例是错误的,因为助手不是无状态的,这使得重用它们变得困难。
关于PHP ZF2 单元测试调度方法非常慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15383073/