Article

Fixture Sets for Rails

Posted  by Blake Watters.

PublicCategorized as Software Development.

Tagged with plugins and rails.

Background

For the last several days I have been feeling the pain of Rails fixtures very accutely. Once your application begins to grow, the expense of maintaining your fixtures becomes higher and higher—often there is a ripple effect in which adding objects to test one part of the app causes assertions to come unglued elsewhere, breaking your development rhythm with cycles of application maintenance. Aside from this, authoring many objects manually by editing YAML can get tedious and time-consuming if you need to work with just a few dozen objects.

For example, at Near-Time we track individual visits to entities within the system. The Visit model that represents the individual accesses is relatively trivial, but uses a polymorphic association for the ‘visitable’ association. Maintaining the visits.yml file can be a serious pain in the ass, since all the tables need to be cross referenced and represented as entities. What is a frustrated, lazy hacker to do? Fixture Sets to the rescue!

Introducing Fixture Sets

Fixture Sets is a plugin for Ruby on Rails that provides two powerful new features that make working with fixtures less painful:
  1. Sandboxed groups of fixtures that can be maintained seperately from the main ‘base’ set of fixtures.
  2. Automatic generation of YAML fixture files from a simple specification file using Active Record finders.

Sandboxed Fixtures

Fixture sets provides a new directory at test/fixture_sets that contains subdirectories with individual groups of YAML files. Instead of declaratively loading each table fixture by fixture using the fixtures method in your tests, you work with an entire group of fixtures at once using the fixture_set class method. Here’s an example:


class FooTest < Test::Unit::TestCase fixture_set :foo

def test_blah
  user = users(:blake)
  visits = Visit.find(:all)
end
end

And the corresponding fixture set looks like this:
$ ls test/fixture_sets/foo
   users.yml  visits.yml  spaces.yml  foo_fixture_set.rb

This provides a higher level abstraction than the per table fixtures and frees you up from the agonizing maintenance cycle that can follow defining new objects. Just make a new set and you are off to the races -- you can even reuse primary key ID's across fixture sets.

Automatic Fixture Generation

In addition to providing sandboxed, named groups of fixtures the Fixture Sets plugin also provides a simple, clean mechanism for extracting fixtures from your development (or production) database into a set of YAML fixtures. A generator is provided to make this process even more straightforward. An example is worth a thousand words:

  $ script/generate fixture_set foo
      exists test/fixture_sets
      create test/fixture_sets/foo
      create test/fixture_sets/foo/foo_fixture_set.rb

And the example fixture set specification:

FixtureSet.define(‘foo’) do |set| User.active = User.find_by_username(‘blaketest’) set.users = User.active set.spaces = User.active.visitable_spaces set.space_users = SpaceUser.find_by_user(User.active) set.pages = Page.with_scope(Scopings.in_my_spaces) { Page.find(:all) }
end

Now we can generate our fixtures using rake:
  $ rake test:fixture_sets:scan
    Generating YAML files for unpopulated Fixture Set ‘foo’
    Generating fixture for tables ‘users’
    Generating fixture for tables ‘spaces’
    Generating fixture for tables ‘space_users’
    Generating fixture for tables ‘pages’

And there you have it, the Fixture Sets plugin in all its glory. This is still a work in progress – additional rake tasks and other fit and finish still need to be ironed out. But it’s functional and in my humble opinion, quite useful.

Please read the README file for more details: https://secure.near-time.com/svn/plugins/trunk/fixture_sets/README

Installing Fixture Sets

Installation is performed via the standard Ruby on Rails plugin script:

  $ script/plugin install https://secure.near-time.com/svn/plugins/trunk/fixture_sets/


Arrow_down Hide comments
  1. danny said 9/19/06  

    Interesting and very useful plugin, but… there is a problem when
    You have constraints in DB. As You may guess fixture loading order
    is then crucial. But don’t worry, here is patched version of
    FixtureSets module. Now fixture order can be specified like this:
    fixture_set :dashboard, :users, :panel,....


    code

    module Test module Unit module FixtureSets # Load a fixture set by name. def fixture_set(name, order) fixture_set_path = FixtureSet.path_for_set(name) raise "Unable to find Fixture Set named #{name} [#{fixture_set_path}]" unless File.exists?(fixture_set_path) fixture_files = FixtureSet.fixtures_for_set(name) raise "No fixtures found in #{fixture_set_path}, have you run rake test:fixture_sets:scan?" if fixture_files.empty? @@original_fixture_path = Test::Unit::TestCase.fixture_path Test::Unit::TestCase.fixture_path = fixture_set_path fixture_symbols = fixture_files.map {|f| f.gsub(’.yml’, ’’).to_sym}
    1. order fixtures list according to the given order keys unless order.empty? ordered = [] order.flatten.each do |o| ord_key = o.to_sym if fixture_symbols.include?(ord_key) ordered<< ord_key fixture_symbols.delete(ord_key) end end ordered += fixture_symbols unless fixture_symbols.empty? fixture_symbols= ordered end end
      end
    fixtures(
    fixture_symbols) end end
    def teardown_with_fixture_set
      Test::Unit::TestCase.fixture_path = @@original_fixture_path
    end
    alias_method :teardown, :teardown_with_fixture_set

  2. danny said 9/19/06  

    Interesting and very useful plugin, but… there is a problem when
    You have constraints in DB. As You may guess fixture loading order
    is then crucial. But don’t worry, here is patched version of
    FixtureSets module. Now fixture order can be specified like this:
    fixture_set :dashboard, :users, :panel,....

    Source is here: http://pastebin.com/789863


  3. Bryan said 10/5/06  

    This looks very useful. Unfortunately, I can’t seem to check out the plugin because Subversion is complaining that it doesn’t support SSL. Is there an alternate way to get at it? I’d rather not have to rebuild svn.


  4. Ryan Norbauer said 3/1/07  

    Bryan: I couldn’t get script/plugin to work either because of the SSL certificate acceptance requirement. I was, however, able to fetch the plugin by navigating to vendor/plugins and running:

    svn export https://secure.near-time.com/svn/plugins/trunk/fixture_sets/


  5. Jeremy said 2/12/09  

    I like the idea of this plugin very much.  I have acquired it via svn checkout.  It seems the plugin uses some deprecated stuff.  Received:

       :0:Warning: Gem::SourceIndex#search support for Regexp patterns is deprecated

    during script/generate fixture_set <setname>.  Is there is anything newer (possibly updated for Rails 2) out there some where?



Powered by Strategy-NetsTerms of Services | Privacy Policy | Security Policy |