Friday, January 4, 2008

Grails Dataset Loaders, aka Test Fixtures

One thing I've been missing since working in Grails is test fixtures ala Rails. The first steps I follow when developing data models is to create test data, which is fairly easy in Rails. For Rails I had to do some extra work to get this data to load into the development db and I also had to augment the yaml files with ERB to generate random data.

The Grails sandbox area has a thread that proposes creating test fixtures that begin in late 2006. As the conversation unfolded, there was a decision to use the term Dataset rather then Fixture--a welcomed change. But the thread kind of died as of October of 2006, so I guess I need to implement this on my own. Here's my attempt...

Datasets and Loaders (Fixtures)
:
I followed the sandbox proposal and created Dataset classes rather than yaml files. Closures were an obvious choice to create datasets, but I also had some other requirements. My objectives were:
  • datasets are usually a single set, but may be separated by dev, test, and production
  • datasets are implemented as closures to enable generating random data
  • dataset loaders may be separated into development, test, and production
  • they can be loaded from within the application on start up
  • they can be loaded on demand from test classes (similar to calling out fixtures)
  • they can be loaded through scripts (ant or grails)
  • they can be loaded from grails shell and console
For all environments a DataLoaderBootStrap class controls loading when the application starts (grails run-app). The bootstrap is environment aware, and loads specified datasets from individual Dataset classes, e.g. UserDataset, CountryDataset, etc. based on the current environment.

The datasets are classes that have a dataset closure that defines hash maps of data (not model classes) and a load() method to do the actual database inserts (or updates). The classes are placed in the src/groovy/datasets folder. Their is a load() method that creates objects from the hash set then invokes "save" to either insert or update depending on the state of the database. This has the benefit of creating predictable data without having to continually drop or trucate tables (ala rails).

When testing in the console, the loaders can be run manually. Test scripts can invoke loaders at any time to insure that there is predictable data. A command line script can be invoked to load all data for the given environment using "grails [env] load-data".

I thought of creating a plugin for this but it doesn't really fit the plugin framework. So, for now I plan to simply keep it as a platform enhancement.

5 comments:

Maximus said...

Do you have an example of this?
I would like to setup fixtures-like environment for my development environment.
I would like to have something I can just run in my HSQLDB instance without needing to have a mySQL instance.

Lance said...

Would it be possible for you to post a diff or detailed explanation of what you did to make this work?

darryl.west said...

Yes, I will gather up what I have and post it here. I'll try to have it by early next week.

Lance said...

Sorry, not long after reading your post I found the Fixtures plugin (http://www.grails.org/Fixtures+Plugin) - which does much of the same of what you spoke.

Lance said...

I blogged about the Fixtures plugin - http://www.brainopolis.com/roller/page/lance/20090203#grails_test_fixtures