Ошибка усечения PHPUnit и MySQL
Я получаю головную боль при работе с PHPUnit, всегда выполняющей TRUNCATE
, перед вставкой приборов без предварительной установки проверки внешнего ключа:
Syntax error or access violation: 1701 Cannot truncate a table referenced in a foreign key constraint
В принципе, PHPUnit пытается обрезать таблицу до того, как она вставляет приборы. Как сообщить об этом SET FOREIGN_KEY_CHECKS=0;
?
Ответы
Ответ 1
Я нашел ответ, кажется. Я закончил переопределять некоторые методы, расширив класс.
<?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.
Ответ 2
В качестве альтернативы вы можете имитировать усечение с комбинацией удаления всех записей и повторной установки счетчика автоматического увеличения.
Сначала вам нужно будет создать новый класс операций базы данных, который будет обрабатывать сброс значения автоматического прироста таблицы.
/**
* 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 и PHPUnit 3.6.10
Ответ 3
\DB::statement('SET FOREIGN_KEY_CHECKS=0;');