繁体   English   中英

如何在没有数据库的情况下模拟ActiveRecord模型规范中的唯一性验证错误?

[英]How can I simulate a uniqueness validation error in an ActiveRecord model spec without the database?

我有一个ActiveRecord模型,它具有唯一性验证:

class Profile < ActiveRecord::Base
  # fields: :name, :slug

  before_validation :set_default_slug_from_name

  validates :slug, uniqueness: {case_sensitive: false},
                   unless: -> { |p| p.slug.blank? }

  # ...
end

现在,在编写此模型的规范时,我想模拟唯一性验证错误, 而不是访问数据库,因此我可以测试一些取决于这样的错误的模型行为:

describe Profile
  before { subject.name = "Bob Greenfield" }

  it "modifies the beginning of the slug if there is a duplicate" do
    # simulate uniqueness conflict (duplicate record) here
    subject.valid?
    expect(subject.slug).to match(/^\w+-bob-greenfield$/)
  end
end

我挖掘了实现UniquenessValidatorRails代码并尝试了以下方法:

allow_any_instance_of(ActiveRecord::Relation).to receive(:exists?).and_return(true)
# ...

但这似乎不起作用。

我想你在这里试图有点太深了。 虽然读取rails源并了解其工作原理非常棒,但是模拟Rails内部使用的每个类实例并不是一个好主意。 在这种情况下,与其他验证器相反,UniquenessValidator确实依赖于数据库,因此您应该:

一种。 允许自己点击数据库。 在这种情况下,这不是一个巨大的开销,也可能是最务实的方法。 你甚至在你的规范中的评论中使用“重复记录”,那么为什么不在那里有记录呢? 在10个案例中的9个案例中,这是正确的方法。 毕竟你正在检查一种ActiveRecord :: Base对象。

检查独立于rails验证的行为。 无论如何应该这样做来测试你喜欢的slug格式。 最好在确认之前确保默认slug有效。 这里的缺点是,在这个调用和实际验证之前有一个很小的机会,slug将由其他人采取,但它与Rails内置的验证相同,所以我不担心它 - 你最终会有错误,下次尝试很可能会成功。

it "modifies the beginning of the slug on validation if there is a duplicate" do
    Profile.stub(:slug_exists?).with("bob-greenfield").and_return(true)
    Profile.stub(:slug_exists?).with("1-bob-greenfield").and_return(true)
    Profile.stub(:slug_exists?).with("2-bob-greenfield").and_return(false)

    subject.set_default_slug_from_name
    subject.slug.should == "2-bob-greenfield"
end

并且您已经知道Rails在验证之前调用,因此您不必测试此行为。

此外,最好确保你对数据库有约束,Rails的唯一性是不够的: http//robots.thoughtbot.com/the-perils-of-uniqueness-validations

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM