【问题标题】:How can I simulate a uniqueness validation error in an ActiveRecord model spec without the database?如何在没有数据库的情况下模拟 ActiveRecord 模型规范中的唯一性验证错误?
【发布时间】:2014-04-23 15:32:32
【问题描述】:

我有一个具有唯一性验证的 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 code 并尝试了以下操作:

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

但这似乎不起作用。

【问题讨论】:

    标签: ruby-on-rails activerecord rspec activemodel


    【解决方案1】:

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

    一个。让自己打数据库。在这种情况下,这并不是一个巨大的开销,并且可能是完成这项工作的最实用的方法。您甚至在规范中的 cmets 中使用“重复记录”,那么为什么不在那里有记录呢?在十分之九的情况下,这是正确的方法。毕竟,您正在检查一种 ActiveRecord::Base 对象。

    b.检查独立于 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      • 1970-01-01
      • 2017-04-01
      • 1970-01-01
      相关资源
      最近更新 更多