2013-03-13 82 views
6

我需要測試一個用ZF2編寫的大網站。有443個測試和約10000個斷言。代碼覆蓋率測試需要6個小時! 我想我發現了這個問題:在控制器的測試中,我使用AbstractHttpControllerTestCase中的一個調度方法。每次測試後,調度方法的執行時間都在增加(從幾分之一秒到幾十秒)。PHP ZF2單元測試調度方法很慢

我使用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(); 
} 

父::派遣是從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 
+0

您是否嘗試過單獨運行每個測試? 'dispatch()'在['AbstractControllerTestCase'](https://github.com/zendframework/Component_ZendTest/blob/master/PHPUnit/Controller/AbstractControllerTestCase。php#L239)('Zend \ Test \ PHPUnit \ Controller') – hakre 2013-03-13 10:51:55

+0

它的工作原理!更快,大約15分鐘,但我在跳過的測試中遇到錯誤: – Kudlaty 2013-03-13 12:10:34

+0

PHPUnit_Framework_Exception:PHP致命錯誤:未收集的異常'Exception''消息''封閉'的序列化不允許'in::44 堆棧跟蹤: (0) - (44):serialize(Array) #1-(348):__phpunit_run_isolated_test() #2 {main} – Kudlaty 2013-03-13 12:10:57

回答

2

兩個Zend\ServiceManagerZend\EventManager大量使用closures。你不能序列化整個應用程序實例,並希望能夠工作,因爲它基本上意味着你試圖序列化服務工廠和定義爲閉包的事件監聽器。

該解決方案可能會使用測試Bootstrap.php,如the one of DoctrineORMModule,它不保留內存中的應用程序實例。 這裏有一個簡單的例子:

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。示例實現可以在herehere中找到。

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應用程序實例是錯誤的,因爲助手不是無狀態的,這使得很難重用它們。

+0

非常感謝這些優秀的解釋! – 2014-01-22 21:58:50