在Rails中加载灯具数据库

时间:2018-09-03 13:38:44

标签: ruby-on-rails postgresql rspec-rails database-cleaner

我正在构建一个Rails应用程序(这是我的新手,如果某些措辞很笨拙,请原谅我)。我正在尝试编写测试(使用RSpec),该测试从数据库中提取和使用数据,并且我无法以简洁的方式编写测试。

某些测试(例如注册用户或创建内容)似乎最适合拥有新的数据库,而有些则需要数据库填充夹具。

此刻,我正在使用具有以下配置的数据库清洁器gem:

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

  # start the transaction strategy as examples are run    
   config.around(:each) do |example|
     DatabaseCleaner.cleaning do
       example.run
     end    
   end

我对两种策略都使用truncation的原因是,我希望示例之间完全刷新id的值(因此,如果我在一个测试中create,然后{ {1}},在第二个测试中,第二个示例的ID应该为create,而不是1)。我不确定各种策略的确切含义-我发现this question似乎用SQL语法来解释它们,但是我对那不是很熟悉,所以我的理解是还是很模糊。我相信数据库是 使用PostgreSQL进行管理,但是我很少需要通过PostgreSQL直接与它进行交互,所以我并不是特别有经验。

因此,在每个示例之间,我的数据库都是完全删除并从头开始构建的-如果我想要一个干净的数据库,那么这是理想的选择,但是如果我想简单地加载固定装置,则可能需要一段时间才能创建所有模型。感觉我应该能够拥有固定装置的“缓存”版本,对于适合的示例,我可以加载该版本。但是我什至不知道如何做到这一点,即使有可能。有办法吗?

编辑:在评论中进行了讨论之后,我怀疑我可能想删除Database Cleaner并改用默认的Rails固定装置。我已经尝试过了,唯一遇到的问题就是上述2策略所遇到的问题。也就是说:当回退测试创建的记录时,transaction不会回退,这是很尴尬的行为。如果出于运行测试的目的创建了id,则将其简称为user是很方便的,如果不重置User.find(1)则是不可能的。

这可能是某种危险信号,我不应该这样做(我愿意做其他事情)。我也意识到我可以说id以获得相同的行为,这可能会更好。我不确定什么合适。

1 个答案:

答案 0 :(得分:1)

DatabaseCleaner不适用于固定装置。它打算与工厂一起使用。 ActiveRecord::Fixtures有其自己的回滚机制。

在概念上有很大的不同。

固定设备就像这组巨大的静态虚拟数据集,每个示例都将它们扔到数据库中,然后通过事务重置。灯具的一大缺点是,您拥有的灯具越多,应用程序的初始状态就越复杂,这会鼓励测试与灯具本身之间的紧密耦合。

这是一个示例,显示了值“ Marko Anastasov”如何从代码外部的某个地方神奇地出现:

RSpec.describe User do
  fixtures :all

  describe "#full_name" do
    it "is composed of first and last name" do
      user = users(:marko)
      expect(user.full_name).to eql "Marko Anastasov"
    end
  end
end

尽管由于近来的简易性(以及Minitest),固定装置已重新流行。

工厂是产生唯一记录的对象工厂。您无需在每个示例周围放置一堆垃圾,而是从一个空白状态开始,然后使用工厂以确切状态填充数据库以复制您正在测试的方案。正确执行此操作可以最大程度地减少测试订购问题,拍动测试和更换夹具断裂测试。

RSpec.describe User do
  describe "#full_name" do
    it "is composed of first and last name" do
      user = FactoryBot.create(:user)
      expect(user.full_name).to eql "#{user.first_name} #{user.last_name}"
    end
  end
end

这是一个可以生成psuedorandom值的好的工厂的示例:

require 'ffaker'

FactoryBot.define do
  factory :user do
    first_name { FFaker::Name.first_name }
    last_name { FFaker::Name.last_name }
  end
end