I learned about the concept of Fixtures when I started looking into the CakePHP framework. I implemented something similar for one of my projects using Pylons.

I’ve been using the Kohana framework for about a week now. It has the performance of Code Igniter, while making some better design decisions imo (like the ability to actually access the GET parameters). Although many people love all the magic that comes with CakePHP (hats off to them for a superb framework!), I prefer to know how the data is traveling through the pipes. This is especially important with new frameworks where sometimes you have to dig into the core to see whats happening.

A test fixture allows you to have a consistent database for testing. Sure you could write a bunch of SQL statements, but that’s not easily maintainable. Read: Schema changes will break your scripts. Fixtures can be XML, JSON, or the newly popular YAML (which I will demonstrate here).

YAML is a human-readable data serialization format. It’s like XML, but without all the braces. Please see the link for more as I want to focus on fixtures for this article.

Great, you’re back. Now back to fixtures. I follow the convention of clearing the database when the test runs and leaving it as is when my test finishes. This allows me the chance to go back into the db if I want to check its state. Besides, wiping the db won’t serve any purpose other than to lose that state.

The most important library is my Fixtures library. It takes a reference to a database instance and a fixtures path. You will then call its load method to load the file into the database. That’s it! I’m using the Spyc library to parse YAML.

I’ll give you the quick flow of things, post snippets of a couple files and package up all the code for your downloading pleasure.

Flow

  1. Unit test controller gets called
  2. Instantiates Fixture class
  3. Loads all YAML files from unit_test config file
  4. Tests run

Code explained

/application/controllers/unit_test.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Unit_test_Controller extends Controller {
 
	const ALLOW_PRODUCTION = FALSE;
 
	// stores database config group to use
	protected $DB_GROUP = NULL;
 
	public function index()
	{
        $this->DB_GROUP = Kohana::config('unit_test.database_group');
 
		// setup a db reference
        $this->db = Database::instance($this->DB_GROUP);
 
		// load fixtures for test
        $this->fixture = new Fixture($this->db, Kohana::config('unit_test.fixtures_path'));
		$fixt_files = Kohana::config('unit_test.load_fixtures');
		foreach ($fixt_files as $fixt){
			$this->fixture->load($fixt);
		}
 
		// Run tests and show results!
		echo new Unit_Test;
	}
}

This is your entry point into the test harness. You’ll call it just like any other controller. While the Database library uses the ‘default’ group defined in /config/database.php, I want to use a separate Database connection. I defined it as ‘test’ and I have defined that name in the /config/unit_test.php file.

It creates a new Fixture object with the database connection and path where it can find my fixtures. Then calls load() for each file defined (in the config file).

Bug: As I am posting this I just found a bug where if you have multiple files that you are loading that use the same table all but the last set of inserts will be removed because I am truncating in the load file. I should just do this to the table once per run.

/application/libraries/Fixture.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Fixture_Core {
    protected $db;
    protected $fixture_path;
 
    function __construct($db, $fixure_path){
        if(!is_dir($fixure_path)){
            exit("{$fixure_path} is not a valid path to fixtures.  Please redefine in config.");
        }
        $this->db = $db;
        $this->fixture_path = $fixure_path;
    }
 
    /*
     * loads fixture data $fixt into corresponding table
     *
     * @param String $fixt Name of fixture file to load (without the extension). Found in the fixtures folder of the test directory
     */
    function load($fixt){
        $Spyc = new Spyc;
        $fixt_data = $Spyc->YAMLLoad($this->fixture_path.DIRECTORY_SEPARATOR.$fixt);
 
        # $fixt_data is supposed to be an associative array outputted by spyc from YAML file
        foreach($fixt_data as $table=>$data){
    	     $this->db->query("TRUNCATE TABLE {$table}");
            foreach($data as $idx=>$row){
                $this->db->insert($table, $row);
            }
        }
    }
}

Here I’m essentially leveraging the parsing of the Spyc library which handles the loading and parsing of the YAML file. Then I’m simply inserting it into the appropriate table.

Hope that helps!!

Download

kohana_test_fixtures.zip