131

I'm attempting to use the new standard way of loading seed data in Rails 2.3.4+, the db:seed rake task.

I'm loading constant data, which is required for my application to really function correctly.

What's the best way to get the db:seed task to run before the tests, so the data is pre-populated?

Luke Francl
  • 31,028
  • 18
  • 69
  • 91

8 Answers8

131

The db:seed rake task primarily just loads the db/seeds.rb script. Therefore just execute that file to load the data.

load "#{Rails.root}/db/seeds.rb"

# or

Rails.application.load_seed

Where to place that depends on what testing framework you are using and whether you want it to be loaded before every test or just once at the beginning. You could put it in a setup call or in a test_helper.rb file.

Ryan McGeary
  • 235,892
  • 13
  • 95
  • 104
ryanb
  • 16,227
  • 5
  • 51
  • 46
  • 5
    I love the simplicity, but for some reason adding this line to my `test_helper.rb` didn't work for me though http://stackoverflow.com/a/1998520/68210 did. – Daniel X Moore Jun 29 '12 at 19:44
  • 39
    In newer versions of rails you can do: Rails.application.load_seed – Steve Jul 09 '13 at 19:11
  • @Steve thank you - do you know where to put Rails.application.load_seed if one is using rspec/capybarra, for example? – BenKoshy Oct 10 '16 at 01:58
  • 1
    @BKSpurgeon I load seed data quite a bit in my applications because it requires specific data to run and the factory is just too complicated. I put `Rails.application.load_seed` right under `require 'rspec/rails'` in my rails_helper file. If you are using database_cleaner gem - it will require a little tweaking to make sure you don't lose your seed data after each test and you can find that in the documentation of the gem it self – MageeWorld Oct 22 '16 at 19:07
  • In Rails 5.x I added this to `test/test_helper.rb` after the existing `require 'rails/test_help'` line – Andrew Aug 08 '19 at 07:25
87

I'd say it should be

namespace :db do
  namespace :test do
    task :prepare => :environment do
      Rake::Task["db:seed"].invoke
    end
  end
end

Because db:test:load is not executed if you have config.active_record.schema_format = :sql (db:test:clone_structure is)

Eugene Bolshakov
  • 2,082
  • 20
  • 8
  • 4
    Running rake with `--trace` helped me understand how this works. – Jared Beck Mar 19 '12 at 01:18
  • 4
    @BookOfGreg I have it in lib/tasks/test_seed.rake that I created myself – Eugene Bolshakov Apr 05 '12 at 06:29
  • Why not run it in db:test:prepare? – Pablo Fernandez May 21 '12 at 08:30
  • 1
    Once I figured out that (a) the rake code can go in lib/tasks/test_seed.rake and (b) it gets run AFTER the standard `rake db:test:prepare task` has completed, this is the winning approach for me. – fearless_fool Aug 23 '12 at 23:20
  • 6
    Why not just this? `task 'db:test:prepare' => 'db:seed'` – Carson Reinke Mar 06 '13 at 15:32
  • This method was working for me just fine all the way through Rails 4.0.0.rc1, but isn't in Rails 4.0.0 (final). Anyone know a fix? Doing a 'rake test --trace' shows that db:seed is being invoked, but my factory_girl factories can't locate the seed data. Inspecting the test DB shows that it's empty, as well! – elsurudo Jul 01 '13 at 13:45
  • 3
    For Rails 4.0.0 final add `ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test'])` before `Rake::Task["db:seed"].invoke` – janic_ Aug 08 '13 at 08:29
  • Note that if any fixture files exist for your models, rails will delete existing data in the table (loaded from seeds.rb or otherwise) for that model and replace it with the YML data before running your tests. It does this even if the YML file is empty. – dafalcon Aug 29 '13 at 14:54
  • 3
    @CarsonReinke - because then the environment when `db:seed` runs is `development`... weirdly. – denishaskin Sep 13 '13 at 15:47
  • 2
    @EugeneBolshakov - actually, same issue with your solution... environment was `development` when `seeds.rb` runs. (Rails 3.2.13 at least) – denishaskin Sep 13 '13 at 15:51
17

Putting something like this in lib/tasks/test_seed.rake should invoke the seed task after db:test:load:

namespace :db do
  namespace :test do
    task :load => :environment do
      Rake::Task["db:seed"].invoke
    end
  end
end
Nick M
  • 279
  • 2
  • 3
17

I believe Steve's comment above should be the correct answer. You can use Rails.application.load_seed to load seed data into your test envoironment. However, when and how often this data is loaded depends on a few things:

Using Minitest

There is no convenient way to run this file once before all tests (see this Github issue). You'll need to load the data once before each test, likely in the setup method of your test files:

# test/models/my_model_test.rb
class LevelTest < ActiveSupport::TestCase

  def setup
    Rails.application.load_seed
  end

  # tests here...

end

Using RSpec

Use RSpec's before(:all) method to load seed data for all test for this model:

describe MyModel do
  before(:all) do
  Rails.application.load_seed
end

describe "my model..." do
  # your tests here
end

Hope this helps.

Community
  • 1
  • 1
Matt
  • 5,800
  • 1
  • 44
  • 40
  • 2
    Best answer so far – Yuri Ghensev Nov 10 '16 at 16:04
  • 1
    I do something similar, except that I'm invoking it in `before(:suite)` instead of `before(:all)`. Posted a separate answer to include formatted code. – Mark Schneider May 27 '20 at 19:20
  • 1
    This is the correct answer, at least for MiniTest. Adding it to `test_helper.rb` results in the seeds file being run multiple times, potentially resulting in errors due to duplicate keys. – johnpitchko Sep 30 '21 at 12:03
4

Building on Matt's answer, if taking that sort of route, I recommend calling Rails.application.load_seed in a before(:suite) block in rspec_helper.rb rather than in a before(:all) block in any file. That way the seeding code is invoked only once for the entire test suite rather than once for each group of tests.

rspec_helper.rb:

RSpec.configure do |config|
  ...
  config.before(:suite) do
    Rails.application.load_seed
  end
  ...
end

Mark Schneider
  • 360
  • 2
  • 10
3

Adding Rake::Task["db:seed"].invoke to the db:test:prepare rake task did not work for me. If I prepared the database with rake db:test:prepare, and then entered the console within the test environment, all my seeds were there. However, the seeds did not persist between my tests.

Adding load "#{Rails.root}/db/seeds.rb" to my setup method worked fine, though.

I would love to get these seeds to load automatically and persist, but I haven't found a way to do that yet!

alexpls
  • 1,914
  • 20
  • 29
3

We're invoking db:seed as a part of db:test:prepare, with:

Rake::Task["db:seed"].invoke

That way, the seed data is loaded once for the entire test run, and not once per test class.

jondahl
  • 121
  • 2
  • 5
3

For those using seedbank, it changes how seeds are loaded, so you probably can't/don't want to use the load ... solution provided here.

And just putting Rake::Task['db:seed'].invoke into test_helper resulted in:

Don't know how to build task 'db:seed' (RuntimeError)

But when we added load_tasks before that, it worked:

MyApp::Application.load_tasks
Rake::Task['db:seed'].invoke
Gary S. Weaver
  • 7,966
  • 4
  • 37
  • 61