ruby-on-rails - 如何在 Rails 中只播种一次测试数据库?
问题描述
我有一个包含 180,000 个单词的大型词典,需要将其加载到数据库中才能运行我的应用程序,并且对测试很有用。不幸的是,这需要大约 30 分钟来为数据库播种。无论如何,是否只为数据库播种一次,或者甚至只为数据库的一个表播种并允许每次运行刷新其他表?
编辑:我最终使用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。
但最好不要写180,000字。
种子和固定装置的问题是它们“一刀切”。它们必须包含所有可能的开发和测试情况。它们很脆弱,对种子的一次更改可能会神秘地破坏许多对固定装置做出假设的测试。如果您需要重置数据库,种子将被吹走。
相反,使用工厂并在需要时创建所需的内容。使用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 字。
推荐阅读
- php - 使用 Plokko Firebase 向多个令牌发送 FCM 通知
- python - 我可以在运行时将 Jenkins 作业阶段添加到管道吗?
- mysql - DROP Table 正在为元数据锁定 MYSQL 提供状态
- laravel - Vue.js/Laravel:将类别 ID 传递给 Vue.js 组件
- javascript - 即使事件是由其子元素触发的,如何仅在父元素上执行回调?
- python - Pandas数据框列值与列表中的元素明智数值比较
- python-3.x - 与 Django 模型中的 postgresql uuid DEFAULT uuid_generate_v4() 有什么相似之处?
- python-3.x - 如何在 Python 中处理大 WAV 文件而不会出现内存错误?
- css - 在 CSS 动画中根据其长度移动文本
- python-3.x - 计算数据框的给定列集中的非零列数 - 熊猫