6

我需要测试一个用 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();
}

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
4

1 回答 1

2

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

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

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

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

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

unset($appConfig);

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;
    }
}

现在,无论您想在测试中的哪个位置,您都可以:

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

$application->bootstrap();

// ...

使用此设置,您可以在绝缘中运行测试。

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

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

于 2013-03-13T15:10:04.133 回答