Auto seed database for testing using Fixtures

12 Sep 2008 In: Code, Kohana

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

Stop polluting my global namespace

11 Sep 2008 In: Code, JavaScript

If it was 1999 and you were telling you’re friends to visit your web site then this post probably wouldn’t fit you.

Luckily for us, it’s not 1999 and calling what I do “building a website” frankly just hurts my feelings (I much prefer web app because web sites were always static pages without much business logic behind it.)

I haven’t lived on this planet long enough to see many programming languages evolve… that is until JavaScript. When I first started building web sites (yes, I called it that back then), the JavaScript I wrote looked like this:

<html>
<head>
<title>Party like it was 1999</title>
<script language="javascript">
<!--
function changeBg(obj, newColor) {
    obj.style.backgroundColor = newColor;
}
-->
</script>
</head>
<body>
<a href="#" onClick="changeBg(this, '#00aaff'); return false;">change background</a>
...

This code makes me cringe! For several reasons. Let me explain…

  1. I never want to see onClick events embedded in your HTML (or presentation markup). Instead, move it to an external file and link it. This goes for the majority of your JavaScript calls, like changeBg() too
  2. You are flooding the global namespace with new functions. Not only is it unmaintainable, it’s also completely devoid of any organization.

The Right Way

Thanks to guys like Paul Buchheit (G-Mail), we have been able to uncover other extremely useful aspects of JavaScript. As JavaScript comes into its own we need to embrace best practices and write beautiful code.

At work, I’ve noticed that while other engineers write great Java code, their JavaScript sometimes looks like a last minute thought. I don’t think this is due to laziness, but rather that they are unaware of the fact that you can apply design patterns to JavaScript just as you would other languages. Usually.

JavaScript Patterns

As I started to write this post I found a bunch of other bloggers already felt the itch and wrote very informative articles on this same topic. So to avoid reinventing the wheel…

Singleton
Module Pattern
Revealing Module Pattern

What did Prototype do?!?

6 Aug 2008 In: Code, JavaScript, Tips

I’ve been using Prototype + Scriptaculous for my current project. It surprises me that I haven’t encountered this problem until just now though.

I noticed some funky behavior today when I tried iterating over an array of values. I have loved Prototype for some time. It’s elegant style, ease of DOM manipulation, and ummm.. it’s style!

However, the behavior I just encountered I don’t care for. I know that Prototype modifies (extends) the builtin objects of Javascript, namely Array and Object. I like the added bang for the buck that I get. But look at this test:

var l_a = ["A","B","C"];
var l_r = "";
for(var l_x in l_a){l_r += l_x + " ";}
alert((l_r == "0 1 2 ") + "\n" + l_r);

What do you think that prints out? Chances are you’re wrong. Read the rest of this entry »

About Me

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!