11

I am developing Unit tests for testing model functions.

I am using PHP PDO with DBUnit 1.1.2 and PHPUnit 3.6.10 and my dataset is a yml file.

I need to turn off foreign key checks while the fixtures are being loaded in the database. After that I need to turn it on again so that I can run my tests under those constraints.

Below is a snippet (not the entire class file) of code in my generalized Testcase file which I will include for any new test case I develop.

When I run a test case under these settings these settings i found that $pdo->exec() is not executing.

What is wrong with my approach? Is there a better alternative?

class MyTestCase extends PHPUnit_Extensions_Database_TestCase {

public function getConnection() {
  $this->pdo = $this->getPDO();

  echo "BEFORE FOREIGN KEY QUERY\n";
  $conn =  $this->createDefaultDBConnection($this->pdo, 'my-schema');
  $this->pdo->exec("set foreign_key_checks=0");

  return $conn;
}

private function getPDO() {
  include BASEPATH . '/application/config/database.php';
  $dbt = $db['testing'];
  $conn_string = sprintf("%s:host=%s;dbname=%s", $dbt['dbdriver'], $dbt['hostname'],     $dbt['database']);
  $pdo = new PDO($conn_string, $dbt['username'], $dbt['password']);
  return $pdo;
}

public function getDataSet() {
  echo "BEFORE FOREIGN KEY QUERY in getDataSet\n";
  $this->pdo->exec("set foreign_key_checks=1");
  return new PHPUnit_Extensions_Database_DataSet_YamlDataSet(ROOTPATH."/application/tests/data/my-dataset.yml");
}

public function setUp() {
   parent::setUp();
}
Abhishek
  • 1,459
  • 3
  • 19
  • 35

3 Answers3

16

Change your function setUp like this

protected function setUp() {
   $conn=$this->getConnection();
   $conn->getConnection()->query("set foreign_key_checks=0");
   parent::setUp();
    $conn->getConnection()->query("set foreign_key_checks=1");
}
  • 2
    This may have worked previously, but not anymore. When DBUnit truncates a table, it will also disable checks, then re-enable it when done. So the checks are always re-enabled prior to any inserts. – Courtney Miles Sep 18 '15 at 01:09
  • 1
    I`ve found exact place, where this is done: [Truncate.php](https://github.com/sebastianbergmann/dbunit/blob/master/src/Extensions/Database/Operation/Truncate.php#L40). If you need to keep behavior from older versions of phpunit, you need to extend default truncate operation class, in a way similar to this: http://stackoverflow.com/a/10331869/1844362, and do something opposite: do not touch foreign keys while truncating. This will give you the ability to disable foreign keys in your way and re-enable when you want. – marcini Oct 05 '15 at 12:14
4

Thanks to the comments from @user2045006 and @marcini, I've created the below solution for my project.

class MyDbTestCase extends PHPUnit_Extensions_Database_TestCase
{
    protected function getConnection()
    {
        // ... as normal ...
    }

    protected function getSetUpOperation()
    {
        // Override
        return new PHPUnit_Extensions_Database_Operation_Composite([
            PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE(),
            new InsertOperationWithoutFkChecks(),
        ]);
    }

}

// Custom subclass
class InsertOperationWithoutFkChecks extends PHPUnit_Extensions_Database_Operation_Insert
{
    public function execute(
        PHPUnit_Extensions_Database_DB_IDatabaseConnection $connection,
        PHPUnit_Extensions_Database_DataSet_IDataSet $dataSet
    ) {
        $connection->getConnection()->exec("SET foreign_key_checks = 0");
        parent::execute($connection, $dataSet);
        $connection->getConnection()->exec("SET foreign_key_checks = 1");
    }
}
LinusR
  • 1,149
  • 10
  • 17
1

Sometimes it can be a case of manually truncating the tables beforehand and ensuring the ordering of your dataset is correct i.e. parent table first and then the reliant child tables. You can then avoid setting foreign_key_checks every test

sufcboy
  • 111
  • 1
  • 1
  • 7