2012-04-26 14 views
14

estoy recibiendo un dolor de cabeza con el comportamiento de PHPUnit de siempre corriendo TRUNCATE antes de accesorios de inserción sin primera configuración de verificación de claves foráneas:PHPUnit y el truncamiento de MySQL error

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

Básicamente, PHPUnit trata de truncar una mesa antes de insertar accesorios. ¿Cómo se lo digo al SET FOREIGN_KEY_CHECKS=0;?

+0

Esto sucede incluso cuando el cuadro de correspondencia entre la tabla que está truncando está vacía. Bastante seguro de que este es un error de MySQL, independientemente de los comentarios aquí: http://bugs.mysql.com/bug.php?id=54678 La solución @Tower es tristemente la única opción. – jmc

Respuesta

27

Encontré la respuesta que parece. Terminé anulando algunos métodos extendiendo una clase.

<?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"); 
    } 
} 

Entonces ejemplo de uso:

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

Así que estoy desactivando efectivamente revisión de las llaves extranjeras y la creación de nuevo si se establecieron nunca. Obviamente, debe crear una clase base que tenga esta funcionalidad y la amplíe en lugar de TestCase de PHPUnit.

+0

¿Dónde está configurando las comprobaciones de claves externas? – Jeune

+0

@Jeune se restablece en TruncateOperation-> execute, tercera línea, donde dice: "SET foreign_key_checks = 1". Encontré este problema en git, que básicamente hace lo mismo, con alguna explicación adicional: [DbUnit GIT] (https://gist.github.com/1319731) – qrazi

+0

Buena solución. Estuve tentado de usar esto, pero como fanático del control, prefiero asegurarme de que los datos se ingresen correctamente frente a relajar las restricciones FK, así que acabo de agregar algunas consultas de eliminación personalizada en el método 'setUp', antes de llamar' parent :: setUp', y funcionó bien. –

3

Como alternativa, puede simular el truncamiento con una combinación de eliminar todos los registros y luego volver a establecer el contador de incremento automático.

En primer lugar, debería crear una nueva clase de operación de base de datos que controlará el restablecimiento del valor de autoincremento de la tabla.

/** 
* 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()); 
      } 
     } 
    } 
} 

ahora sobrescribir los métodos getSetUpOperation() y getTearDownOperation() como se describe anteriormente.

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

a mí me funcionó con MySQL 5.5.24 y 3.6.10 PHPUnit

Cuestiones relacionadas