如何自动将db:seed数据加载到测试数据库中?

131

我正尝试使用Rails 2.3.4+中的新标准种子数据加载方法,即db:seed rake任务。

我正在加载必须的常量数据,以使我的应用程序能够正常运行。

如何在测试之前让db:seed任务运行,以便数据预填充?

8个回答

131

db:seed rake 任务主要只是加载 db/seeds.rb 脚本。因此,只需执行该文件即可加载数据。

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

# or

Rails.application.load_seed

放置的位置取决于您使用的测试框架以及是否希望在每次测试之前加载它或仅在开始时加载一次。您可以将其放在setup调用中或者在test_helper.rb文件中。


5
我喜欢这种简单的方法,但是不知为何,将这行代码添加到我的 test_helper.rb 中并没有起作用,不过 https://dev59.com/R3I_5IYBdhLWcg3wAd82#1998520 这个链接里的方法可行。 - Daniel X Moore
39
在较新的Rails版本中,您可以执行以下操作:Rails.application.load_seed。 - Steve
@Steve 谢谢 - 你知道如果我们在使用rspec/capybara的话,Rails.application.load_seed应该放在哪里吗? - BenKoshy
1
@BKSpurgeon 我在我的应用程序中经常加载种子数据,因为它需要特定的数据才能运行,而工厂则太复杂了。我将 Rails.application.load_seed 放在我的 rails_helper 文件中的 require 'rspec/rails' 正下方。如果您正在使用 database_cleaner gem,则需要进行一些调整,以确保您不会在每个测试后丢失种子数据,您可以在 gem 的文档中找到相关信息。 - MageeWorld
在Rails 5.x中,我在现有的require 'rails/test_help'行后添加了以下内容到test/test_helper.rb文件中。 - Andrew

87

我认为应该是这样

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

由于config.active_record.schema_format = :sql,因此如果你设置了该选项,db:test:load 不会被执行(但是 db:test:clone_structure 会被执行)。


4
使用--trace参数运行rake命令帮助我理解了它的工作原理。 - Jared Beck
4
@BookOfGreg 我已经在lib/tasks/test_seed.rake文件中创建了它。 - Eugene Bolshakov
6
为什么不直接这样写呢?task 'db:test:prepare' => 'db:seed' - Carson Reinke
3
在Rails 4.0.0 final版本中,在执行 Rake::Task["db:seed"].invoke 前添加 ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) - janic_
3
@CarsonReinke - 因为当运行 db:seed 时,环境通常是 development......非常奇怪。 - denishaskin
显示剩余5条评论

17

我认为Steve's comment是正确答案。你可以使用Rails.application.load_seed将种子数据加载到测试环境中。然而,何时以及多久加载此数据取决于一些因素:

使用Minitest

没有方便的方法在所有测试之前运行此文件(请参见this Github issue)。您需要在每个测试之前加载数据,很可能是在测试文件的设置方法中:

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

  def setup
    Rails.application.load_seed
  end

  # tests here...

end

使用 RSpec

使用 RSpec 的 before(:all) 方法为此模型的所有测试加载种子数据:

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

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

希望这可以帮助到您。

2
到目前为止最佳答案 - Yuri Ghensev
1
我做了类似的事情,不同的是我在 before(:suite) 中调用它而不是 before(:all)。发布了一个单独的答案来包括格式化代码。 - Mark Schneider
1
这是正确的答案,至少对于MiniTest而言。将其添加到test_helper.rb中会导致种子文件被多次运行,可能会因为重复键而产生错误。 - johnpitchko

17

在 lib/tasks/test_seed.rake 中放置以下内容,应该会在 db:test:load 之后调用种子任务:

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

4

在Matt的回答基础上,如果采用这种方式,我建议在rspec_helper.rb中的before(:suite)块中调用Rails.application.load_seed,而不是在任何文件中的before(:all)块中。这样,播种代码仅会为整个测试套件调用一次,而不是为每组测试调用一次。

rspec_helper.rb:

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


3

对于使用种子库的用户,它会改变种子的加载方式,所以您可能不能/不想使用这里提供的load ...解决方案。

而只是将Rake::Task['db:seed'].invoke放入test_helper中会导致以下结果:

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

但是在加入load_tasks之前,它并没有起作用:
MyApp::Application.load_tasks
Rake::Task['db:seed'].invoke

3
我们将db:seed作为db:test:prepare的一部分调用,使用如下命令:Rake::Task["db:seed"].invoke。这样,种子数据只会在整个测试运行期间加载一次,而不是每个测试类都加载一次。

5
你是否创建了一个新的db:test:prepare任务来完成这个操作?你能够发布一下代码吗? - Luke Francl

3

db:test:prepare rake task中添加Rake::Task["db:seed"].invoke对我没有用。如果我使用rake db:test:prepare来准备数据库,然后在测试环境下进入控制台,我的所有种子数据都会出现。但是,这些种子数据在我的测试之间没有持久化。

不过,在我的设置方法中添加load "#{Rails.root}/db/seeds.rb"就可以正常工作。

我希望能够自动加载和持久化这些种子数据,但我还没有找到合适的方法!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接