Auto-load the seed data from db/seeds.rb with rake

2019-01-22 13:42发布

问题:

I'm using rails-rspec gem and I have several specs (models, controllers, etc). When I run:

bundle exec rake

everything is tested. However, I would like to improve my specs by seeding some data (from db/seeds.rb) just after the database is created (in test environment).

My spec/spec_helper.rb file looks like this:

ENV["RAILS_ENV"] ||= 'test'

require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'capybara/rspec'
require 'ruby-debug'

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|
  config.mock_with :rspec

  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  config.include SpecHelper

  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.start
    stub_xmpp_rest_client!  
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  config.include Devise::TestHelpers, :type => :controller
  config.include Delorean
  config.after(:each) { back_to_the_present }
  config.include Factory::Syntax::Methods
  config.extend ControllerMacros, :type => :controller
end

What could do the best way to do so? Thanks.

回答1:

Depending on how your seed file is configured, you might just be able to load/run it from a before(:each) or before(:all) block:

load Rails.root + "db/seeds.rb" 


回答2:

Bad idea! Never, ever, seed your test database. Use factories to create, within each test, only the records necessary for that test to pass. Seeding the test database will make your tests less reliable, because you'll be making lots of assumptions that aren't explicitly stated in your tests.



回答3:

I set up my rake spec task to automatically load db/seeds.rb, so I depend on that for setting up the database for a first run. Add this to your Rakefile:

task :spec     => "db:seed"
task :cucumber => "db:seed"

Then, on subsequent runs I just call rspec spec directly to skip the seed step and avoid unnecessary reloading. I configure database cleaner to ignore the seed tables like this:

RSpec.configure do |config|

  config.add_setting(:seed_tables)
  config.seed_tables = %w(countries roles product_types)

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation, except: config.seed_tables)
  end

  config.around(:each) do |example|
    if example.metadata[:no_transactions]
      DatabaseCleaner.strategy = :truncation, {except: config.seed_tables}
    else
      DatabaseCleaner.strategy = :transaction
    end
    DatabaseCleaner.start
    example.run
    DatabaseCleaner.clean
  end
end

For scenarios that need committed data, I can add:

describe "commit for real", use_transactions: false do
  # ...
end

This will truncate everything after the example runs, except the seed tables. It's assumed that you never write anything to the seed tables! This is generally a safe assumption, since seed data is typically static.

For all other normal scenarios, I depend on transactions to roll back any inserted records. The database is returned to the original state, with the data in the seed tables intact. It's safe to write to the seed tables here if you need to.

To rebuild the seed tables, you just need to run rake spec again.



回答4:

To load seeds in rspec you need to add it after database cleanup in confg.before(:suite) in spec_helper

config.before(:suite) do
  DatabaseCleaner.clean_with(:truncation)
  load "#{Rails.root}/db/seeds.rb" 
end


回答5:

In Rails 4.2.0 and RSpec 3.x, this is how my rails_helper.rb looks.

RSpec.configure do |config|
  config.include FactoryGirl::Syntax::Methods
  # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
  config.fixture_path = "#{::Rails.root}/spec/fixtures"

  # If you're not using ActiveRecord, or you'd prefer not to run each of your
  # examples within a transaction, remove the following line or assign false
  # instead of true.
  config.use_transactional_fixtures = false

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

  config.before(:all) do
    Rails.application.load_seed # loading seeds
  end
end


回答6:

  1. copy the seed.rb file inside the config/initializers folder.So seed.rb file will be executed on server start.

  2. Run the below command to fill the test db with the seed.rb data

    RAILS_ENV=test rake db:seed



回答7:

I think we should use

config.before(:each) do
  Rails.application.load_seed # loading seeds
end

as before(:all) runs the block one time before all of the examples are run.

So if we use before :all, the seed data will be cleared.