2012-04-30 25 views
8

मैं PHPUnit/DBUnit के साथ कुछ वास्तविक गति समस्याओं में भाग रहा हूं। PHPUnit_Extensions_Database_TestCase विस्तारित करने वाली कुछ भी हमेशा के लिए चलती है। 18 9 परीक्षणों के साथ, सुइट में लगभग 8-9 मिनट लगते हैं। मैं उम्मीद करता था कि इसमें अधिकतम 30 सेकंड लगेंगे ;-)मैं अपने PHPUnit + DBUnit परीक्षण सूट निष्पादन को कैसे बढ़ा सकता हूं?

ऐसा लगता है कि डेटाबेस को प्रारंभिक स्थिति में बहाल करने की प्रक्रिया है, जो समय लेता है, इसलिए हमने अपने डेटासेट को यथासंभव छोटा और सीमित कर दिया है प्रत्येक परीक्षण मामले के लिए हमें आवश्यक तालिकाओं की संख्या। मैं फिक्स्चर का उपयोग कर रहा हूं और जितना संभव हो साझा कर रहा हूं।

क्या कोई सेटिंग या संशोधन है जिसका उपयोग मैं निष्पादन को गति देने के लिए कर सकता हूं? यह देखकर कि MySQL सर्वर पूरे परीक्षण में क्या कर रहा है, ऐसा लगता है कि बहुत सारे कटाव/डालने का काम हो रहा है, लेकिन निश्चित रूप से परीक्षण डेटा सेट को अस्थायी तालिकाओं में पैक करना और फिर प्रत्येक परीक्षण के लिए उन्हें चुनना तेज होगा?

मैं जिस ड्राइवर का उपयोग कर रहा हूं वह एक एक्सएमएल परीक्षण डेटासेट के साथ पीडीओ/माईएसक्यूएल है।

+0

आपको जहां मीट्रिक है वहां मीट्रिक की आवश्यकता है। यदि आप पूरे डेटाबेस का नकल कर सकते हैं तो शायद यह आपकी आवश्यकताओं को तेज करेगा ताकि आपको डब्यूनिट चलाने की आवश्यकता न हो। एक परीक्षा 10 वीं के तहत चलनी चाहिए - जो वास्तव में एक परीक्षण के लिए काफी धीमी है। – hakre

+0

चूंकि आपने उल्लेख नहीं किया है, क्या आप फिक्स्चर का उपयोग कर रहे हैं और जितना संभव हो साझा कर रहे हैं? – Pradeep

+0

मैं फिक्स्चर का उपयोग कर रहा हूं और जितना संभव हो उतना साझा कर रहा हूं। क्या कोई तरीका है कि मैं परीक्षण धावक प्रोफाइल कर सकता हूं? –

उत्तर

18

गुगलिंग पर मैंने 10 मिनट से 1 मिनट तक के समय को कम करने में कामयाब रहा है। यह पता चला है कि my.ini/my.cnf में कुछ InnoDB कॉन्फ़िगरेशन सेटिंग्स को बदलने से मदद मिलेगी।

innodb_flush_log_at_trx_commit = 2 सेट करना नौकरी लगता है। इसे बदलने के बाद, अपना MySQL सर्वर पुनरारंभ करें। dev.mysql.com: innodb_flush_log_at_trx_commit

सेटिंग नियंत्रण पर

अधिक कैसे एसिड लॉग के फ्लशिंग है संगत। डिफ़ॉल्ट मान 1 है जो पूर्ण एसीआईडी ​​अनुपालन है जिसका अर्थ है

लॉग बफर प्रत्येक लेनदेन प्रतिबद्धता पर लॉग फ़ाइल में लिखा जाता है और डिस्क फ़ाइल पर फ्लश लॉग फ़ाइल पर किया जाता है।

2 के एक मूल्य के साथ, निम्न होता है:

लॉग बफ़र प्रत्येक प्रतिबद्ध में फाइल करने के लिए लिखा है, लेकिन डिस्क संचालन के लिए फ्लश उस पर नहीं किया जाता है।

यहां महत्वपूर्ण अंतर यह है कि चूंकि प्रत्येक प्रतिबद्धता पर लॉग लिखा नहीं जाता है, इसलिए एक ऑपरेटिंग सिस्टम क्रैश या पावर आउटेज इसे मिटा सकता है। उत्पादन के लिए, 1 के मान से चिपके रहें। परीक्षण डेटाबेस के साथ स्थानीय विकास के लिए, 2 का मान सुरक्षित होना चाहिए।

आप डेटा है कि लाइव डेटाबेस को हस्तांतरित किया जाएगा के साथ काम कर रहे हैं, मैं के 1.

+0

बहुत धन्यवाद - यह मेरा समय 90% तक ले गया! अजीब हालांकि मेरी टेबल माईसाम हैं ... शायद यह आंतरिक टेबल है? – ChrisA

+2

हाँ, ऐसा लगता है कि चमत्कार ... बस इसे [mysqld] अनुभाग (कहीं और नहीं) के नीचे रखना सुनिश्चित करें। – anroots

+0

यह वास्तव में pgsql द्वारा मदद नहीं करता है :-(बीटीडब्ल्यू मुझे लगता है कि डबुनिट सुक्स, यह बेहद धीमी है .. – inf3rno

1

मूल्य DbUnit में स्थिरता निर्माण बेहद धीमी गति से है के साथ चिपके हुए सुझाव है। यह 1.5 सेकंड core2duo E8400 4GB किंग्स्टन 1333. के साथ हर समय लगता है आप xdebug साथ टोंटी पा सकते हैं और इसे ठीक कर (यदि आप कर सकते हैं), या आप निम्न में से एक कर सकते हैं:

1.)

आप वर्तमान में एक कस्टम बूटस्ट्रैप xml:

<?xml version="1.0" encoding="UTF-8"?> 
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
     xsi:noNamespaceSchemaLocation="http://phpunit.de/phpunit.xsd" 
     backupGlobals="false" 
     verbose="true" 
     bootstrap="test/bootstrap.php"> 
    <testsuites> 
     <testsuite> 
      <directory>test/integration</directory> 
      <exclude>test/integration/database/RoleDataTest.php</exclude> 
     </testsuite> 
    </testsuites> 
    <php> 
     <env name="APPLICATION_MODE" value="test"/> 
    </php> 
</phpunit> 

बहिष्कृत भाग यहां महत्वपूर्ण है। आप परीक्षण समूहों का भी उपयोग कर सकते हैं।

2।)

namespace test\integration; 


abstract class AbstractTestCase extends \PHPUnit_Extensions_Database_TestCase 
{ 
    static protected $pdo; 
    static protected $connection; 

    /** 
    * @return \PHPUnit_Extensions_Database_DB_IDatabaseConnection 
    */ 
    public function getConnection() 
    { 
     if (!isset(static::$pdo)) { 
      static::$pdo = new \PDO('pgsql:host=localhost;port=5432;dbname=dobra_test', 'postgres', 'inflames', array(\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION)); 
      static::$connection = $this->createDefaultDBConnection(static::$pdo); 
     } 
     return static::$connection; 
    } 

    /** 
    * @return \PHPUnit_Extensions_Database_Operation_DatabaseOperation 
    */ 

    static protected $fixtureSet = false; 

    protected function getSetUpOperation() 
    { 
     $c = get_class($this; 
     if (!$c::$fixtureSet) { 
      $c::$fixtureSet = true; 
      return \PHPUnit_Extensions_Database_Operation_Factory::CLEAN_INSERT(true); 
     } 
     return \PHPUnit_Extensions_Database_Operation_Factory::NONE(); 
    } 

    static protected $dataSet; 

    /** 
    * @return \PHPUnit_Extensions_Database_DataSet_IDataSet 
    */ 
    public function getDataSet() 
    { 
     $c = get_class($this; 
     if (!isset($c::$dataSet)) { 
      $c::$dataSet = $this->createDataSet(); 
     } 
     return $c::$dataSet; 
    } 

    /** 
    * @return \PHPUnit_Extensions_Database_DataSet_IDataSet 
    */ 
    abstract protected function createDataSet(); 

    protected function dataSetToRows($tableName, array $ids) 
    { 
     $transformer = new DataSetRowsTransformer($this->getDataSet()); 
     $transformer->findRowsByIds($tableName, $ids); 
     $transformer->cutColumnPrefix(); 
     return $transformer->getRows(); 
    } 

} 

आप टेस्टकेस को ओवरराइड कर सकते हैं। इस उदाहरण में आप प्रत्येक टेस्ट केस द्वारा केवल एक पीडीओ कनेक्शन का उपयोग करेंगे (आप इसे निर्भरता इंजेक्शन के साथ अपने कोड में इंजेक्ट कर सकते हैं), सेटअप ऑपरेशन को ओवरराइड करके आप केवल टेस्टकेस में केवल एक बार स्थिरता सेट कर सकते हैं या प्रत्येक टेस्ट के लिए केवल एक बार (self:: पर निर्भर करता है या $cls = get_class($this); $cls::)। (PHPUnit में खराब डिज़ाइन है, यह प्रत्येक टेस्ट कॉल द्वारा नया उदाहरण बनाता है, इसलिए आपको प्रति उदाहरण या प्रति वर्ग चर को स्टोर करने के लिए कक्षा के नामों के साथ हैक करना होगा।) इस परिदृश्य से आपको @depend एनोटेशन के साथ एक दूसरे पर निर्भर रहने के लिए परीक्षण लिखना होगा। । उदाहरण के लिए आप पिछले परीक्षण में बनाई गई एक ही पंक्ति को हटा सकते हैं।

इस परीक्षण कोड 1.5 secs बजाय 6 x 1.5 = 9 secs द्वारा:

namespace test\integration\database; 

use Authorization\PermissionData; 
use test\integration\AbstractTestCase; 
use test\integration\ArrayDataSet; 

class PermissionDataTest extends AbstractTestCase 
{ 
    static protected $fixtureSet = false; 
    static protected $dataSet; 

    /** @var PermissionData */ 
    protected $permissionData; 

    /** 
    * @return \PHPUnit_Extensions_Database_DataSet_IDataSet 
    */ 
    public function createDataSet() 
    { 
     return new ArrayDataSet(array(
      'permission' => array(
       array('permission_id' => '1', 'permission_method' => 'GET', 'permission_resource' => '^/$'), 
       array('permission_id' => '2', 'permission_method' => 'POST', 'permission_resource' => '^/$'), 
       array('permission_id' => '3', 'permission_method' => 'DELETE', 'permission_resource' => '^/$') 
      ), 
      'user' => array(
       array('user_id' => '1', 'user_name' => 'Jánszky László', 'user_email' => '[email protected]', 'user_salt' => '12435') 
      ), 
      'user_permission' => array(
       array('user_permission_id' => '1', 'user_id' => '1', 'permission_id' => '1'), 
       array('user_permission_id' => '2', 'user_id' => '1', 'permission_id' => '2') 
      ), 
      'role' => array(
       array('role_id' => '1', 'role_name' => 'admin') 
      ), 
      'role_permission' => array(
       array('role_permission_id' => '1', 'role_id' => '1', 'permission_id' => '1') 
      ), 
      'permission_cache' => array(
       array('permission_cache_id' => '1', 'user_id' => '1', 'permission_id' => '1'), 
       array('permission_cache_id' => '2', 'user_id' => '1', 'permission_id' => '2'), 
      ) 
     )); 
    } 

    public function testReadAllShouldReturnEveryRow() 
    { 
     $this->assertEquals($this->permissionData->readAll(), $this->dataSetToRows('permission', array(3, 2, 1))); 
    } 

    /** @depends testReadAllShouldReturnEveryRow */ 

    public function testReadAllByRoleIdShouldReturnEveryRowRelatedToRoleId() 
    { 
     $this->assertEquals($this->permissionData->readAllByRoleId(1), $this->dataSetToRows('permission', array(1))); 
    } 

    /** @depends testReadAllByRoleIdShouldReturnEveryRowRelatedToRoleId */ 

    public function testReadAllByUserIdShouldReturnEveryRowRelatedToUserId() 
    { 
     $this->assertEquals($this->permissionData->readAllByUserId(1), $this->dataSetToRows('permission', array(2, 1))); 
    } 

    /** @depends testReadAllByUserIdShouldReturnEveryRowRelatedToUserId */ 

    public function testCreateShouldAddNewRow() 
    { 
     $method = 'PUT'; 
     $resource = '^/$'; 
     $createdRow = $this->permissionData->create($method, $resource); 
     $this->assertTrue($createdRow['id'] > 0); 
     $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount() + 1, $this->getConnection()->getRowCount('permission')); 
     return $createdRow; 
    } 

    /** @depends testCreateShouldAddNewRow */ 

    public function testDeleteShouldRemoveRow(array $createdRow) 
    { 
     $this->permissionData->delete($createdRow['id']); 
     $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount(), $this->getConnection()->getRowCount('permission')); 
    } 

    /** @depends testDeleteShouldRemoveRow */ 

    public function testDeleteShouldRemoveRowAndRelations() 
    { 
     $this->permissionData->delete(1); 
     $this->assertEquals($this->getDataSet()->getTable('permission')->getRowCount() - 1, $this->getConnection()->getRowCount('permission')); 
     $this->assertEquals($this->getDataSet()->getTable('user_permission')->getRowCount() - 1, $this->getConnection()->getRowCount('user_permission')); 
     $this->assertEquals($this->getDataSet()->getTable('role_permission')->getRowCount() - 1, $this->getConnection()->getRowCount('role_permission')); 
     $this->assertEquals($this->getDataSet()->getTable('permission_cache')->getRowCount() - 1, $this->getConnection()->getRowCount('permission_cache')); 
    } 

    public function setUp() 
    { 
     parent::setUp(); 
     $this->permissionData = new PermissionData($this->getConnection()->getConnection()); 
    } 
} 

3.)

केवल एक बार परियोजना प्रति दृढ़ बनाने के लिए एक अन्य समाधान है, और उस प्रयोग के बाद हर परीक्षण लेन-देन में और हर के बाद रोलबैक परीक्षा। (यह काम नहीं करता है यदि आपके पास pgsql स्थगित कोड है जो बाधाओं की जांच करने के लिए प्रतिबद्धता की आवश्यकता है।)