November 21, 2006

Posted by John

Older: Class and Instance Variables In Ruby

Newer: Testing A Multi-Site Application

Fixture Groups

I’m working on a pretty big project right now that has a lot of fixtures to load. What I noticed today is that most of these fixtures could be grouped together to make loading them easier. Take below for example:

context "Posting A Valid Page to admin/pages/create" do
  fixtures :users, :authorizations, :roles, :permissions, :rights, :sites, :sections, :section_sites, :pages

Here I’m creating a functional test that makes sure everything is ok when I try to create a page (I’ll spare you the details of the test). Because this is in the administration area, I need to authorize the request which means I’ll need a user to authorize as and all the permissions and such that they have. This means I need to load the authentication and authorization fixtures which are :users, :authorizations, :roles, :permissions, :rights.

Also, the project is a multi-site application so I need to know which site I’m working with and what sections that site uses so I have to load the site and section fixtures which are :sites, :sections, :section_sites.

Finally, I need to load the page fixtures (wow, I’m starting to hate fixtures but that is another post) so I add :pages. Ok, so finally I ended up with the fixtures call that I posted above. Now this isn’t that bad except when you have several contexts that you are testing the controller in. I need to have the auth and site fixtures for each of these contexts which means I have to repeat myself several times. Not to mention that nearly every controller is going to need the site and auth fixtures.

What I Did

Well, fixtures is a class method that gets added to Test::Unit::TestCase and as you may know it accepts a list of table names. It doesn’t care how it gets the table names, just that it has something to work with. Knowing that, I added two class methods in test_helper.rb:

class Test::Unit::TestCase
  class << self
    def auth_fixtures
      [:users, :authorizations, :roles, :permissions, :rights]
    def site_fixtures
      [auth_fixtures, :sites, :sections, :section_sites].flatten

The first method returns an array of all the fixtures that I need for authentication and authorization. The second returns all the fixtures I need for dealing with sites. You’ll notice that it actually calls the auth_fixtures method because everytime I’m dealing with sites, I will most likely need the auth fixtures as well. Now I can do the following:

context "Posting A Valid Page to admin/pages/create" do
  fixtures site_fixtures, :pages

This shortens up the fixture list but works the exact same as the length one. Does anyone else know of an easier or more “proper” way of grouping fixtures like this? This is working great for me, but if I’m off my rocker, let me know in the comments. I may pluginize something like this, but I’ll see what the general reaction is before I get too far in.

I was thinking something like…

class Test::Unit::TestCase
  fixture_groups  :auth => [:users, :authorizations, :roles, :permissions, :rights],
                  :site => [auth_fixtures, :sites, :sections, :section_sites]

…which would define methods like I did in the article might be kind of handy. Anyway, let me know what you all think.


  1. Alain Ravet Alain Ravet

    Nov 22, 2006

    After seeing it used in Mephisto code, I started loading ALL the fixtures at once, every time, and I noticed my tests ran faster that when I was loading only the necessary fixtures individually. Go figure.
    I use this code:

  2. Hmmm…that is odd. Doesn’t seem like that would be the case. Can anyone else confirm that? Next time I’m in the project I’ll give it a try with Geoff’s test timer.

Sorry, comments are closed for this article to ease the burden of pruning spam.


Authored by John Nunemaker (Noo-neh-maker), a programmer who has fallen deeply in love with Ruby. Learn More.


Release your software more often with fewer problems.
Flip your features.