16

I am currently using PHPUnit and DBUnit for my project. I have a problem in DBUnit because DBUnit PHPUnit_Extensions_Database_TestCase­Src class does not seem to be truncating the existing data on the test db. So this makes my insertion tests fail after only working for one time.

I am using mysql and here is my code :

abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase
{
    // only instantiate pdo once for test clean-up/fixture load
    static private $pdo = null;

    // only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once per test
    private $conn = null;

    final public function getConnection()
    {
        if ($this->conn === null) {
            if (self::$pdo == null) {
                self::$pdo = new PDO( "mysql:dbname=db;host=localhost", "root", "pass" );
            }
            $this->conn = $this->createDefaultDBConnection(self::$pdo, "db");
        }

        return $this->conn;
    }
}

class DbopTest extends Generic_Tests_DatabaseTestCase
{       
    private $db;

    protected function setup(){
        $this->db = null;
    }

    public function getDataSet(){
        return $this->createMySQLXMLDataSet(dirname(__FILE__) . '/../rows.xml');
    }       
    ...
}

So how can I fix this problem? What is it that I do wrong here?

hakre
  • 193,403
  • 52
  • 435
  • 836
LostMohican
  • 3,082
  • 7
  • 29
  • 38
  • Where does the wished truncation take's place? Which version of PHPUnit and which version of DBUnit are you using? – hakre Feb 28 '12 at 22:10
  • thats the problem, i think in my getDataSet method, truncation operates automatically. But I cant see that happen. I am using PHP Unit 3.6.10. – LostMohican Feb 29 '12 at 11:48
  • 4
    It's just a guess, but you're overwriting the `setUp()` method. Please check if `getDataSet()` is still being called. – hakre Feb 29 '12 at 15:04
  • yeah, when i call the parent::setup the problem is fixed, good guess ; ) – LostMohican Feb 29 '12 at 21:52
  • 1
    +1 Useful question because of the use of getDataSet and use of Generic DataTest class! – eddy147 Aug 02 '12 at 06:53

4 Answers4

38

If you override the setUp method, PHPUnit won't automatically call your getDataSet method. You need to take care that you call the parent::setUp method as well, otherwise PHPUnit does not know what to do ;).

hakre
  • 193,403
  • 52
  • 435
  • 836
  • 3
    I am not overriding the setUp method in my tests, but it's still not truncating the table. At what point does DBUnit actually truncate the database? – AgmLauncher Aug 07 '15 at 15:39
5

I came across this issue myself and this is how I resolved it after a bit of digging into the PHPUnit sourcecode. It looks like the default behavior for the PHPUnit_Extensions_Database_TestCase class is to return PHPUnit_Extensions_Database_Operation_Factory::NONE(). For what you need, and how the PHPUnit document seems to imply how it's supposed to work, you'll want to override the method to return PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE().

Luckily, this is fairly straight-forward. You just need to add the following to your TestCase class.

protected function getTearDownOperation()
{
    return \PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}

Before this I was manually truncating tables in my Teardown() method, but I think you'll agree that this solution is much better.

yichengli
  • 51
  • 1
  • 2
  • This method definitely works but in `"phpunit/phpunit": "^7.0.0"` and `"phpunit/dbunit": "^4.0"` you need to use `return \PHPUnit\DbUnit\Operation\Factory::TRUNCATE();` – DazBaldwin Feb 08 '19 at 12:50
1

Not expecting many too kudos for this answer, but I have spent several hours trying to figure out why one of my test database tables was not getting truncated, causing the same duplicate entry error described above. My getDataSet() looked like

function getDataSet() {

    $files = array('languages','interpreters','interp_languages',
        'interp_events','deft_events',
           //etc
    );

    $dataSets = array();
    foreach ($files as $file) {
        $dataSets[] = new PHPUnit_Extensions_Database_DataSet_MysqlXmlDataSet(
         $this->files_dir."/$file.xml");
    }

    return new PHPUnit_Extensions_Database_DataSet_CompositeDataSet($dataSets);
}

and the technique was working fine on other test classes. It happens that I inadvertentely left out one of my xml data file names from $files, therefore DbUnit was not loading that data file, ergo not truncating the table. But because there were plenty of rows left over in the table from other tests that were using that same data file, it was not obvious (to me) what was happening.

Hope it saves someone else from tearing her/his eyeballs out some day.

David
  • 815
  • 8
  • 18
0

You need to have a getDataSet() method otherwise PHPUnit assumes you have no data to fixturize.

http://www.phpunit.de/manual/3.6/en/database.html

The getDataSet() method defines how the initial state of the database should look before each test is executed. The state of a database is abstracted through the concepts DataSet and DataTable both being represented by the interfaces PHPUnit_Extensions_Database_DataSet_IDataSet and PHPUnit_Extensions_Database_DataSet_IDataTable. The next section will describe in detail how these concepts work and what the benefits are for using them in database testing.

For the implementation we only need to know that the getDataSet() method is called once during setUp() to retrieve the fixture data-set and insert it into the database. In the example we are using a factory method createFlatXMLDataSet($filename) that represents a data-set through an XML representation.

Community
  • 1
  • 1
Mike B
  • 31,886
  • 13
  • 87
  • 111