
Fixtures are notorious in rails. To get around issues like brittleness and multiple file flipping to understand single test, there have been better approaches using gems like fixture_replacement, machinist and factory_girl. No complains there. In my experience, fixture are still great for one thing: loading seed data. This is because seed data is often used by many many tests and they don’t change often and hence won’t cause tests to be brittle. Another great advantage of fixtures is that any fixture data is loaded once and only once for the entire test run.
Rails 2.3.4 includes a new rake task for loading seed data called db:seed. It suggests keeping all seed data as a ruby code inside of db/seeds.rb file. The issue with this is this is not DRY. You have duplicate set of representation for seed data: one side of seeds.rb and one in fixture files (.yml). Keeping them in sync is a pain and all the other disadvantages that come with not having single source of truth.
Problem
To have single source of seed data and be able to load that seed data once and only once for the entire test run.
Solution 1: Use Fixtures:
Advantage: Fixture are ideal since fixture files (.yml) get loaded once and only one before the tests start running.
Disadvantage: requires duplicating seed data that is already coded in db/seeds.rb into .yml files. We might try to get around this by having another rake task that converts data inside seeds.rb into .yml files or vice versa. In any case, it feels like a hack.
Solution 2: Load seeds.rb as part of test
# test/test_helper.rb
module TestHelper
def load_seed_data
load File.dirname(__FILE__) + '/../db/seeds.rb'
end
end
class ActiveSupport::TestCase
include TestHelper
endAdvantage: loads the seed data from same seeds.rb and eliminates duplicating them into fixture files (.yml).
Disadvantage: load_seed_data has to be called once before each single test and data is loaded and discarded as part of each test. This impacts test runs greatly and is not scalable as codebase and hence tests grow.
The Solution: call db:seed as part of db:test:prepare
Rails executes db:test:prepare when tests are run. This solution entails adding a hook to run db:seed as part of this. This ensures that the seed data from seeds.rb is loaded before the tests start. One caveat here is disable fixture loaded by deleting all .yml files, otherwise it will delete the seed data loaded here.
namespace :db do
namespace :test do
task :prepare => :environment do
Rake::Task["db:seed"].invoke
end
end
endAdvantage: Re-uses seeds.rb, loads seed data into test database only once for entire test run
Disadvantage: none so far.
Caveats:
- While running individual tests or test files (as part of invoking test from inside IDE), we need to ensure that test database is already loaded with seed data. This can be easily done using “db:reset” rake task on test environment.
- The .yml files have to be deleted from test/fixtures folder. If any .yml file exists, rails will delete the data from the table corresponding to that file as part of test setup. This will happen even if the file is empty and does not contain any seed data.
Clean and DRY. That feels good.

[...] Ruby/Rails: Loading Seed Data for Tests | Pathfinder Development | Software Developers | Blogs [...]