Database Fixtures for Isolated Testing in PHP

Long ago, Ryan wrote the history of our fixture frameworks. Now, you too can have the awesome Team Lazer Beez database fixture for your own project. With the release of Team Lazer Beez Open Source (formerly Genius Open Source) version 1.2, our YAML-backed, easy-to-setup fixture framework has been integrated into the gosTest framework.

Here is a simple example from our Fixture package:

<?php
// Include the Genius config file
require_once dirname(dirname(__FILE__)) . '/Core/gosConfig.inc.php';
 
/**
 * A function to get single values from a database table
 */
function getThingFromDB($id) {
    $db = gosDB_Helper::getDBByName('main');
 
    return $db->getOne("SELECT s1 FROM fixture_test WHERE i1 = " . $id);
}

In a nearby test file:

<?php
// Include the Genius fixture configuration. This geneartes a database
// and applies the schema to it.  See fixtureTestConfig.inc.php
// for more details.
require_once(GOS_ROOT . 'Fixture/fixtureTestConfig.inc.php');
 
function testGetThingFromDB() {
    // Create a fixture
    $fixture = gosTest_Fixture_Controller::getByDBName('main');
 
    // Load the fixture into the database
    $fixture->parseFixtureFile(GOS_ROOT . 'Fixture/example_fixture.yaml');
 
    // Directly access the fixture, which is identical to what the database contains
    $idToGet = $fixture->get('fixtureName.fixture_test.i1');
 
    // Pull the value we want directly from the fixture
    $fixtureThing = $fixture->get('fixtureName.fixture_test.s1');
    // Pull the value we want from the DB via the function we're testing
    $thing = getThingFromDB($idToGet);
 
    echo "The fixture put $fixtureThing into the DB.\n";
    echo "Our function selected $thing from the DB.\n";
}
 
// Run the test
testGetThingFromDB();

The first magical line here is that require_once—fixtureTestConfig.inc.php uses the database connection information defined in Fixture/fixtureConfig.yaml to create a database is used for the duration of this PHP process only. Subsequent test runs (or invocations of this example script) will generate an entirely new database. See gosDB_AutoDBGenerator for details on these ephemeral databases. The takeaway is that you must have a user listed in that fixture config YAML file that can create databases.

In the test function itself, we create a fixture on the appropriate database, in this case our main database, and load the data from our fixture file, a simple YAML file defining what data we want in the database:

# The name of this fixture
fixtureName:
    # A table we will insert data into
    fixture_test:
        i1: 11
        s1: str1

At this point, we’re ready to start testing. First we get the ID that we need to pass to getThingFromDB, which we simply pull from the fixture. Next, we get the value that we are expecting from the same table in the fixture. Now that we have the ID we want to give to the function we’re testing, and the value we expect to get back, we can execute that function and compare the results. Go ahead and try this all for yourself; the above example works all on its own. The easiest way is to download the example.php and the necessary YAML file.

The gosFixture class automatically cleans up the database tables that it touched (see Core/lib/gosTest/Framework/TestCase.acls.php), so you need to re-apply the fixture for every test. The easiest way to do this is to put the fixture initialization in the setUpExtension() of a test class, giving you completely fresh fixture data for each and every test.

So go forth and test your code with better isolation and known clean data.

  • Digg
  • StumbleUpon
  • del.icio.us
  • Facebook
  • Twitter
  • Google Bookmarks
  • DZone
  • HackerNews
  • LinkedIn
  • Reddit