如何在 Rails 中仅播种一次测试数据库?

How to seed Test db just once in Rails?

我有一本包含 180,000 个单词的大词典,需要将其加载到数据库中才能使我的应用 运行 并且对测试很有用。不幸的是,这需要大约 30 分钟来为数据库播种。无论如何只播种数据库一次,或者甚至只播种数据库的一个 table 并允许每个 运行 刷​​新其他 tables?

编辑:我最终使用 activerecord-import 大大加快了播种过程。现在需要 16 秒而不是半小时。我还注意到在我的 /spec/rails_helper.rb 文件中有以下内容:

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

我显然很久以前就添加了它,但忘记了它,因为这是我使用的一种模板 rails_helper 文件。注释掉意味着我不会每次都 运行 它,如果我确实需要重新播种我可以,只需取消注释即可。

出于某种原因,我错误地认为 rspec 只是默认播种,但事实并非如此。

您可以使用新的 Rails 6 insert_all 提高播种效率。这会使用单个 insert 创建多个记录,并且不会实例化模型。 OTOH 它不做任何验证,所以要小心。

DictionaryWords.insert_all([
  { word: "foo" },
  { word: "bar" },
])

或者,使用 activerecord-import


不过18万字还是别造的好

种子和固定装置的问题是它们 "one size fits all"。它们必须包含所有可能的开发和测试情况。它们很脆弱,对种子的一个改变可能会神秘地破坏许多对固定装置做出假设的测试。如果您需要重置数据库,种子将被吹走。

相反,使用 factory and create what you need when you need it. Use a library such as Faker 生成虚假但有效的数据。

例如...

# Assuming you have classes called Dictionary and DictionaryWord
factory :dictionary do
end

factory :dictionary_word do
  dictionary
  word { Faker::Lorem.unique.word }
end

然后在测试中根据需要创建单词。我在这里使用 RSpec.

let(:dictionary) { create(:dictionary) }
let!(:words) { create_list(:dictionary_word, 3, dictionary: dictionary) }

context 'when the word is in the dictionary' do
  let(:word) { words.sample }

  it 'finds the word' do
    expect( dictionary.exists?(word) ).to be_truthy
  end
end

context 'when the word is not in the dictionary' do
  let(:word) { "septemburary" }

  it 'does not find the word' do
    expect( dictionary.exists?(word) ).to be_falsey
  end
end

如果手动测试需要更多的话,请打开控制台并制作一些。

[1] pry(main)> FactoryBot.create_list(:dictionary_words, 100)

这不是特别有效,但您可能真的不需要 180,000 个单词。


我想你可以运行一次。

  1. 第一次你应该运行测试环境的种子

    RAILS_ENV=测试railsdb:seed

  2. 现在运行RSpec