The World Through the Eyes of John Brennan
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.
/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!!
Code. Design. Explore. is the blog of John Brennan, a web developer/designer, entrepreneur, and avid world traveler. I currently live in Brooklyn, NY.
I am the Co-Founder of OpenAction and lead Product Development. We are a open platform social enterprise that helps organizations engage with donors, share knowledge with other non profits and empower the community to get involved to create positive impact on our planet.
This blog will mostly be around building cool things, although I will surely include my travel experiences when I am abroad. Feel free to subscribe to a specific category if that is only what interests you. And please connect with me. I always enjoy meeting new, interesting people!
marekdec
January 29th, 2010 at 9:16 am
cool article, though a sample yaml fixture is missing…