PHP ZF2单元测试调度方法非常慢

Kud*_*aty 6 php phpunit unit-testing zend-test zend-framework2

我需要测试用ZF2编写的大型网站.有443个测试和大约10000个断言.使用代码覆盖测试需要6个小时!我想我发现了问题:在控制器的测试中,我使用了AbstractHttpControllerTestCase的调度方法.每次测试后(从秒到数十秒的分数),调度方法的执行时间都在增加.

我使用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();
}
Run Code Online (Sandbox Code Playgroud)

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);
Run Code Online (Sandbox Code Playgroud)

请帮忙.谢谢.


更新:

我使用进程隔离和测试在大约15分钟内完成(没有代码覆盖)但我在测试中得到标记为跳过的错误:

PHPUnit_Framework_Exception: PHP Fatal error:  Uncaught exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in -:44
Run Code Online (Sandbox Code Playgroud)

Ocr*_*ius 2

Zend\ServiceManagerZend\EventManager大量使用了闭包。您不能序列化整个应用程序实例并期望它能够工作,因为这基本上意味着您尝试序列化定义为闭包的服务工厂和事件侦听器。

Bootstrap.php解决方案可能是使用类似DoctrineORMModule 的测试,它不会将应用程序实例保留在内存中。这是一个简化的示例:

require_once __DIR__ . '/../vendor/autoload.php';

$appConfig = require __DIR__ . '/TestConfiguration.php';

\YourModuleTest\Util\ServiceManagerFactory::setConfig($appConfig);

unset($appConfig);
Run Code Online (Sandbox Code Playgroud)

TestConfiguration应该看起来像标准 mvc 应用程序的配置

您还需要ServiceManagerFactory. 示例实现可以在此处此处找到。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,无论您想要在测试中的任何位置,您都可以:

$serviceManager = \YourModuleTest\Util\ServiceManagerFactory::getServiceManager();
$application    = $serviceManager->get('Application');

$application->bootstrap();

// ...
Run Code Online (Sandbox Code Playgroud)

通过此设置,您可以在绝缘状态下运行测试。

另一方面,您应该首先关注真正的单元测试,因为 ZF2 确实简化了您组合复杂对象的方式。您还应该正确设置覆盖过滤器,以便不处理不相关的代码(这可能会占用大量时间)。

此外,重复使用 mvc 应用程序实例是错误的,因为助手不是无状态的,这使得它们很难重用。