【问题标题】:Auto-load the seed data from db/seeds.rb with rake使用 rake 从 db/seeds.rb 自动加载种子数据
【发布时间】:2011-12-05 14:15:00
【问题描述】:

我正在使用rails-rspec gem,我有几个规格(模型、控制器等)。当我跑步时:

bundle exec rake

一切都经过测试。但是,我想在数据库创建后(在测试环境中)通过播种一些数据(来自 db/seeds.rb)来改进我的规范。

我的 spec/spec_helper.rb 文件如下所示:

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

最好的方法是什么?谢谢。

【问题讨论】:

    标签: ruby-on-rails-3 testing rspec rake


    【解决方案1】:

    坏主意!永远不要播种您的测试数据库。使用工厂在每个测试中创建该测试通过所需的记录。为测试数据库添加种子会使您的测试不太可靠,因为您会做出许多测试中未明确说明的假设。

    【讨论】:

    • 我同意你的看法,@marnen-laibow-koser。但是,如您所知,种子的目的是减少对应用程序至关重要的数据。这就是为什么我认为它对测试场景很有用。
    • 我不明白不包括种子数据的态度。它和代码一样是应用程序的一部分,只是它恰好存储在数据库中。它应该只存在于所有测试中。
    • @DavidN.Welton 你错了。种子数据不是应用程序的一部分,与任何其他数据一样。 no 测试应该存在生产种子数据,因为包含它会远远超出测试运行所需的最小设置。 应该提供的是最少的精心制作的数据(通常不超过 10 条记录)——刚好足以让测试通过。如果你为测试创建数据库,你最终会得到脆弱、不清楚、紧密耦合的测试——测试不应该是所有的东西。这不是“态度”;这是一个可以证明的事实。
    • 我们中的一些人正在构建与......现实耦合的系统,其中耦合需要相当强。大多数情况下,我不想在我的测试中使用种子数据,但有时你会这样做,在这种情况下,很高兴找到一种优雅的方式来做这件事。例如,我的应用程序有一些常量值存储在数据库中而不是 Ruby CONSTANTS 中,它们需要参与测试。
    • @TarynEast 那么我认为你做错了,可能是因为你并不真正了解你的方法的缺点。使用 db/seeds 文件,您可以清除地毯下的种子,从而使您的假设隐含。在测试中,这不好。每个测试都应该明确其假设,而做到这一点的方法是在每个测试中从零开始,并创建您需要该测试的记录。工厂定义通常不会比种子文件复杂,并且可能不那么复杂。 (另外,您自己指出您正在滥用 db/seeds。)
    【解决方案2】:

    根据您的种子文件的配置方式,您可能只能从 before(:each)before(:all) 块加载/运行它:

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

    【讨论】:

    • 今天同一行可以这样写 Rails.application.load_seed
    【解决方案3】:

    我将我的rake spec 任务设置为自动加载 db/seeds.rb,因此我依赖它来设置数据库以进行首次运行。将此添加到您的 Rakefile:

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

    然后,在随后的运行中,我只需直接调用 rspec spec 以跳过种子步骤并避免不必要的重新加载。我将数据库清理器配置为忽略种子表,如下所示:

    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
    

    对于需要提交数据的场景,我可以补充:

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

    这将在示例运行后截断所有内容,除了种子表。 假设您从未向种子表写入任何内容!这通常是一个安全的假设,因为种子数据通常是静态的。

    对于所有其他正常情况,我依靠事务来回滚任何插入的记录。数据库恢复到原始状态,种子表中的数据完好无损。如果需要,可以安全地在此处写入种子表。

    要重建种子表,您只需再次运行rake spec

    【讨论】:

    • 我们正在管理一个充斥着固定装置和假设的测试套件,并将其转移到更加基于工厂的设置。将我们的种子数据从固定装置中移出并进入这个一次性设置策略是其中的关键部分 - 感谢您的回答,它帮助我们完成了一些实施
    • 它对我有用(Rails 4 和很多东西要加载到种子上)。谢谢。今天你是我的英雄。
    【解决方案4】:

    要在 rspec 中加载种子,您​​需要在 confg.before(:suite) 中的数据库清理之后添加它 spec_helper

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

    【讨论】:

      【解决方案5】:

      Rails 4.2.0RSpec 3.x 中,这是我的 rails_helper.rb 的外观。

      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. 将seed.rb 文件复制到config/initializers 文件夹中。这样seed.rb 文件将在服务器启动时执行。

        2. 运行下面的命令用seed.rb数据填充测试数据库

          RAILS_ENV=test rake db:seed

        【讨论】:

          【解决方案7】:

          我认为我们应该使用

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

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

          所以如果我们使用before :all,种子数据将被清除。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-06-05
            • 2018-03-16
            • 1970-01-01
            • 1970-01-01
            • 2011-08-13
            • 1970-01-01
            • 2014-08-16
            • 1970-01-01
            相关资源
            最近更新 更多