2012-04-26 3 views
14

Je reçois un mal de tête avec le comportement de PHPUnit de toujours en cours d'exécution TRUNCATE avant fixtures insertion sans premier réglage de contrôles clés étrangers au large:PHPUnit et erreur troncature MySQL

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

Fondamentalement, PHPUnit tente de tronquer une tableau avant qu'il insère des appareils. Comment puis-je le dire à SET FOREIGN_KEY_CHECKS=0;?

+0

Cela se produit même lorsque la table faisant référence à la table que vous tronquer est vide. Assez sûr que c'est un bug MySQL, indépendamment des commentaires ici: http://bugs.mysql.com/bug.php?id=54678 La solution @Tower est malheureusement la seule option. – jmc

Répondre

27

J'ai trouvé la réponse, il semble. J'ai fini par remplacer certaines méthodes en étendant une classe.

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

Ensuite, un exemple d'utilisation:

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

Je suis effectivement désactiver la vérification des clés étrangères et les mettre en arrière si jamais ils étaient fixés. Évidemment, vous devriez créer une classe de base qui a cette fonctionnalité et l'étendre plutôt que TestCase de PHPUnit.

+0

Où réglez-vous les vérifications de clés étrangères? – Jeune

+0

@Jeune il est réinitialisé dans TruncateOperation-> execute, troisième ligne, où il va: "SET foreign_key_checks = 1". Trouvé ce problème sur git, qui fait essentiellement la même chose, avec quelques explications supplémentaires: [DbUnit GIT] (https://gist.github.com/1319731) – qrazi

+0

Belle solution. J'ai été tenté de l'utiliser, mais en tant que monstre de contrôle, je préférerais que les données soient entrées correctement par rapport aux contraintes FK, donc j'ai juste ajouté quelques requêtes de suppression personnalisées dans la méthode 'setUp' avant d'appeler' parent :: setUp', et a bien fonctionné. –

3

Vous pouvez également simuler une troncature en combinant la suppression de tous les enregistrements et la réinitialisation du compteur d'incrémentation automatique. Tout d'abord, vous devez créer une nouvelle classe d'opérations de base de données qui gérera la réinitialisation de la valeur d'incrémentation automatique de la table.

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

, écrasez maintenant les méthodes getSetUpOperation() et getTearDownOperation() comme décrit ci-dessus.

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

travaillé pour moi avec MySQL 5.5.24 et 3.6.10 PHPUnit