如何使用Rspec对where子句进行测试时,对Active Record关系进行存根化?

8

我有一个类,看起来像这样:

class Foo < ActiveRecrod::Base
  has_many :bars

  def nasty_bars_present?
    bars.where(bar_type: "Nasty").any?
  end

  validate :validate_nasty_bars
  def validate_nasty_bars
    if nasty_bars_present?
      errors.add(:base, :nasty_bars_present)
    end
  end
end

在测试#nasty_bars_present?方法时,我想编写一个rspec测试来存根bars关联,但允许where自然执行。类似于:

describe "#nasty_bars_present?" do
  context "with nasty bars" do
    before { foo.stub(:bars).and_return([mock(Bar, bar_type: "Nasty")]) }
    it "should return true" do
      expect(foo.nasty_bars_present?).to be_true
    end
  end
end

上面的测试给出了一个有关数组没有where方法的错误。我该如何包装mock以便where能够适当地执行呢?
谢谢!

你使用的是哪个版本的RSpec? - nikkon226
这个项目是在2.14.1上进行的,但我也对在最新版本上执行感兴趣。 - biagidp
1个回答

6
对于RSpec 2.14.1(也适用于RSpec 3.1),我建议尝试这样做:
describe "#nasty_bars_present?" do
  context "with nasty bars" do
    before :each do
      foo = Foo.new
      bar = double("Bar")
      allow(bar).to receive(:where).with({bar_type: "Nasty"}).and_return([double("Bar", bar_type: "Nasty")])
      allow(foo).to receive(:bars).and_return(bar)
    end
    it "should return true" do
      expect(foo.nasty_bars_present?).to be_true
    end
  end
end

这样,如果您在where语句中没有指定条件调用bars.where(bar_type: "Nasty"),则不会获得带有bar_type: "Nasty"的重复酒吧。这对于未来模拟酒吧(至少返回单个实例,对于多个实例,您将添加另一个double)可能是可重用的。


1
“double('Bar')” 应该改为 “class_double('Bar')” 吗? - dimitry_n

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接