2012-04-26 88 views
14

我得到一個頭痛中總是插入夾具之前運行TRUNCATE沒有第一設置外鍵檢查關PHPUnit的行爲:的PHPUnit和MySQL截斷誤差

Syntax error or access violation: 1701 Cannot truncate a table referenced in a foreign key constraint

基本上,PHPUnit的嘗試截斷在插入燈具之前的表格。我如何把它告訴SET FOREIGN_KEY_CHECKS=0;

+0

發生這種情況即使在引用表格中你截斷表是空的。很確定這是一個MySQL錯誤,無論這裏的評論如何: http://bugs.mysql.com/bug.php?id=54678 @Tower解決方案是可悲的唯一選擇。 – jmc 2014-04-19 10:44:11

回答

27

我發現似乎的答案。我最終通過擴展一個類來覆蓋一些方法。

<?php 

/** 
* Disables foreign key checks temporarily. 
*/ 
class TruncateOperation extends \PHPUnit_Extensions_Database_Operation_Truncate 
{ 
    public function execute(\PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, \PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) 
    { 
     $connection->getConnection()->query("SET foreign_key_checks = 0"); 
     parent::execute($connection, $dataSet); 
     $connection->getConnection()->query("SET foreign_key_checks = 1"); 
    } 
} 

然後使用例子:

class FooTest extends \PHPUnit_Extensions_Database_TestCase 
{ 
    public function getSetUpOperation() 
    { 
     $cascadeTruncates = true; // If you want cascading truncates, false otherwise. If unsure choose false. 

     return new \PHPUnit_Extensions_Database_Operation_Composite(array(
      new TruncateOperation($cascadeTruncates), 
      \PHPUnit_Extensions_Database_Operation_Factory::INSERT() 
     )); 
    } 
} 

所以我有效地禁用外鍵檢查和設置他們回來,如果他們有沒有設置。顯然,你應該創建一個具有此功能的基類,並且擴展它而不是PHPUnit的TestCase。

+0

你在哪裏設置外鍵檢查? – Jeune 2012-05-23 06:06:21

+0

@June它在TruncateOperation-> execute中重置,第三行,它在那裏:「SET foreign_key_checks = 1」。在git上發現了這個問題,基本上也是這樣,並附加一些解釋:[DbUnit GIT](https://gist.github.com/1319731) – qrazi 2012-11-27 14:43:36

+0

很好的解決方案。我很想使用它,但作爲一個控制怪胎,我寧願確保數據輸入正確與放寬FK約束,所以我只是在'setUp'方法中添加了一些自定義刪除查詢,然後再調用'parent :: setUp',並且工作正常。 – 2013-03-01 18:37:36

3

或者,您可以通過刪除所有記錄並重新設置自動增加計數器的組合來模擬截斷。

首先,您將不得不創建新的數據庫操作類來處理重置表的自動增量值。如上所述

/** 
* Resets all AUTO_INCREMENT counters on all tables in a dataset. 
* @see PHPUnit_Extensions_Database_Operation_IDatabaseOperation 
*/ 
class ResetAutoincrementOperation implements PHPUnit_Extensions_Database_Operation_IDatabaseOperation 
{ 

    /* 
    * @see PHPUnit_Extensions_Database_Operation_IDatabaseOperation::execute() 
    */ 
    public function execute(PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection, 
      PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet) 
    { 
     foreach ($dataSet->getReverseIterator() as $table) { 
      $query = "ALTER TABLE {$connection->quoteSchemaObject($table->getTableMetaData()->getTableName())}" 
       . " AUTO_INCREMENT = 1 
      "; 

      try { 
       $connection->getConnection()->query($query); 
      } catch (PDOException $e) { 
       throw new PHPUnit_Extensions_Database_Operation_Exception('RESET_AUTOINCREMENT', 
         $query, array(), $table, $e->getMessage()); 
      } 
     } 
    } 
} 

現在覆蓋getSetUpOperation()getTearDownOperation()方法。

class FooTest extends PHPUnit_Extensions_Database_TestCase 
{ 
    /** 
    * @see PHPUnit_Extensions_Database_TestCase::getTearDownOperation() 
    */ 
    protected function getTearDownOperation() 
    { 
     // Clean up after ourselves 
     return new PHPUnit_Extensions_Database_Operation_Composite(array(
      PHPUnit_Extensions_Database_Operation_Factory::DELETE_ALL(), // 1. delete all records from table 
      new ResetAutoincrementOperation() // 2. reset auto increment value 
     )); 
    } 

    /** 
    * @see PHPUnit_Extensions_Database_TestCase::getSetUpOperation() 
    */ 
    protected function getSetUpOperation() 
    { 
     return new PHPUnit_Extensions_Database_Operation_Composite(array(
       PHPUnit_Extensions_Database_Operation_Factory::DELETE_ALL(), // 1. delete all records from table 
       new ResetAutoincrementOperation(), // 2. reset auto increment value 
       PHPUnit_Extensions_Database_Operation_Factory::INSERT() // 3. insert new records 
     )); 
    } 
} 

爲我工作與MySQL 5.5.24和3.6.10的PHPUnit