lundi 11 juillet 2016

PHPUnit DBUnit doesn't seem to use getDataSet to insert fixture between tests

I am facing a strange problem with my PHPUnit/DBUnit tests.

My local machine : PHP 5.5, MySQL 5.5, PHPUnit 5.4 and DBUnit 2.0
My CI server : PHP 5.6, MySQL 5.5, PHPUnit 5.4 and DBUnit 2.0.

Here is my setUp(), getConnection() and getDataSet() methods:

/**
 * @return PHPUnit_Extensions_Database_DB_IDatabaseConnection
 */
public function getConnection()
{
    if ($this->conn === null) {
        // $GLOBALS['core']->db is a PDO instance. 
        // Not a good idea to use that kind of stuff, but for now, 
        // the custom framework we are using needs it.
        $this->conn = $this->createDefaultDBConnection(
            $GLOBALS['core']->db, 
            'test_db');
    }

    return $this->conn;
}

/**
 * @return PHPUnit_Extensions_Database_DataSet_IDataSet
 */
public function getDataSet()
{
    $base_seed_data_set = new PHPUnit_Extensions_Database_DataSet_YamlDataSet(
        dirname(__FILE__)."/fixtures/base-seed.yml"
    );

    return $base_seed_data_set;
}

/**
 * Prepares the environment before running a test.
 */
public function setUp ()
{
    // Dirty stuff again, but same as for getConnection(), 
    // our custom framework needs it for the moment...
    @session_start();
    parent::setUp();
    LoginHelper::logUser(1);
}

On my local machine, everything works fine. My tests are run, my fixtures are used to initialize my database between each test, and my tests are passing.

However, I tried running those same tests on my future continuous integration server, and the tests don't pass. DBUnit fails to assert that the database matches my expected dataset in one of my tests.

In both cases, configuration is provided via the same phpunit.xml :

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="phpunit_bootstrap.php" 
    backupGlobals="false" 
    backupStaticAttributes="false">
    <php>
        <var name="DB_DSN" value="mysql:dbname=test_db;host=localhost" />
        <var name="DB_USER" value="test" />
        <var name="DB_PASSWD" value="test" />
        <var name="DB_DBNAME" value="test_db" />
    </php>
    <testsuites>
        <testsuite name="My test suite">
            <!-- This directory contains my test file and a fixtures folder -->
            <directory>tests/MyTest</directory>
        </testsuite>
    </testsuites>
    <logging>
        <log type="coverage-html" target="build/coverage"/>
        <log type="coverage-clover" target="build/logs/clover.xml"/>
        <log type="coverage-crap4j" target="build/logs/crap4j.xml"/>
        <log type="junit" target="build/logs/junit.xml" 
            logIncompleteSkipped="false"/>
    </logging>
</phpunit>

So I tried to launch the failing test alone : it passes.

I tried to change the order of my tests : the previously failing test passes, but other tests that were previously passing now fail.

I figured that the database is not properly initialized between tests. It is only initialized using the fixture provided in my getDataSet() method on the first test. The rest of the test hence use the database as the previous test left it. That is obviously a bad thing, as the tests are not independant and have an effect on each other.

I tried to trace the execution of my tests by putting log messages in some methods, and it appears that my getDataSet() method is called before and after every test. It seems to follow this pattern :

setUp()
getConnection()
getDataSet()
testOne()
getDataSet()

setUp()
getConnection()
getDataSet()
testTwo()
getDataSet()
...

I noticed I didn't use the same PHP version on my local machine and CI server. I tried to downgrade my CI server PHP only to achieve the same result.

I'm stuck with this weird behaviour that nobody seems to encounter... What am I doing wrong?

Aucun commentaire:

Enregistrer un commentaire