Ruby on rails 在Rails中加载设备数据库

Ruby on rails 在Rails中加载设备数据库,ruby-on-rails,postgresql,rspec-rails,database-cleaner,Ruby On Rails,Postgresql,Rspec Rails,Database Cleaner,我正在构建一个Rails应用程序(我是新手,所以请原谅我有些措词笨拙)。我正在尝试编写(使用RSpec)从数据库中提取和使用数据的测试,但在以简洁的方式编写测试时遇到了困难 有些测试(如注册用户或创建内容)似乎最适合拥有一个新的数据库,而有些测试则需要一个数据库 目前,我正在使用数据库清理器gem,配置如下: config.before(:suite) do DatabaseCleaner.clean_with(:truncation) DatabaseCleaner.str

我正在构建一个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
我对这两种策略都使用
截断
的原因是我更喜欢在两个示例之间完全刷新
id
值(这样,如果我在一个测试中
create
,然后在第二个测试中
create
,那么第二个示例应该具有id
1
而不是
2
)。我不确定各种策略的确切含义是什么——我已经找到了用SQL语法来解释它们的方法,但我对它不是很熟悉,所以我的理解仍然很模糊。我相信数据库是正确的 使用PostgreSQL进行管理,但我很少直接通过它与之交互,所以我不是特别有经验

因此,我的数据库在每个示例之间都是完全删除和从头开始构建的-如果我想要一个干净的数据库,那么这是理想的,但是如果我只想加载装置,那么创建所有模型可能需要一段时间。我觉得我应该能够有一个“缓存”版本的装置,我可以加载这些适合的例子。但如果可能的话,我不知道该怎么做。有办法吗

编辑:在评论中讨论之后,我怀疑我可能想删除数据库清理器,而使用默认的Rails装置。我已经试过了,唯一的问题就是我与上面描述的
事务
策略相同。也就是说:当回滚测试创建的记录时,
id
不会回滚,这是一种尴尬的行为。如果为了运行测试而创建一个
用户
,可以方便地将其称为
user.find(1)
,如果
id
没有重置,这是不可能的


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

DatabaseCleaner不适用于固定装置。它打算用于工厂。有自己的回滚机制

在概念上有很大的不同

fixture类似于这一庞大的静态虚拟数据集,每个示例都会将其抛出数据库,然后通过事务重置。fixture的最大缺点是,您拥有的fixture越多,应用程序的初始状态就越复杂,这鼓励了测试和fixture本身之间的紧密耦合

这是一个显示值“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
这是一个生成伪随机值的良好工厂示例:

require 'ffaker'

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

谢谢你的回答!事实上,固定装置和工厂是不同的东西,当我认为它们合适的时候,我碰巧在使用它们。有些测试(比如从头开始创建内容)感觉更像“工厂式”,有些测试感觉更像“固定装置式”(我想要测试的行为感觉它取决于数据库的内容)。我会仔细阅读你链接的页面,如果我仍然不清楚该怎么做,我会回到这里。我真的不会把它们混在一起——你可以用两者来实现相同的目标,但在同一个项目中使用两者不会很好。实际上,你只是去除了装置的唯一优点,即简单性/速度。尤其是因为使用DatabaseCleaner与ActiveRecord::Fixtures不兼容,会造成混乱。我明白了。我想我更喜欢使用fixture,因为我对测试感兴趣的大多数行为感觉它在某种程度上依赖于数据库结构,这使得基于工厂的测试很难编写。但在一些行为更简单的地方,使用工厂感觉更好,因为这样我知道夹具的任何特殊功能都不会让测试“碰巧”通过。我将尝试从我的项目中删除DBCleaner,看看回滚是否按我所希望的方式工作。顺便问一下,是什么使它们“不兼容”?我在问题中添加了一些细节(以避免注释混乱)