RSpec的存根问题



我正在努力理解为什么这些测试的结果,第一个测试声称该方法没有被存根,然而,第二个是。

class Roll
  def initialize
    install if !installed?
  end
  def install; puts 'install'; end
end
describe Roll do
  before do
    class RollTestClass < Roll; end
    RollTestClass.any_instance.stub(:install)
  end
  let(:roll_class) { RollTestClass }
  let(:roll) { RollTestClass.new }
  context 'when installed is true' do
    before do
      roll_class.any_instance.stub(:installed?).and_return(true)
    end
    it 'should not call install' do
      expect(roll).to_not have_received(:install)
    end
  end
  context 'when installed is false' do
    before do
      roll_class.any_instance.stub(:installed?).and_return(false)
    end
    it 'should call install' do
      expect(roll).to have_received(:install)
    end
  end
end

错误显示expected to have received install也很奇怪,但我认为这可能只是来自RSpec DSL的错误反馈。但也许值得注意。

  1) Roll when installed is true should not call install
     Failure/Error: expect(roll).to_not have_received(:install)
       #<RollTestClass:0x10f69ef78> expected to have received install, but that method has not been stubbed.

RSpec的"间谍模式"要求对象之前已被存根。然而,any_instance.stub实际上并不会"真正地"存根方法,除非/直到在特定对象上调用该方法。因此,这些方法显示为"未缓冲",您将得到所得到的错误。这里有一些代码演示了定义的变化:

class Foo
end
describe "" do
  it "" do
    Foo.any_instance.stub(:bar)
    foo1 = Foo.new
    foo2 = Foo.new
    print_bars = -> (context) {puts "#{context}, foo1#bar is #{foo1.method(:bar)}, foo2#bar is #{foo2.method(:bar)}"}
    print_bars['before call']
    foo1.bar
    print_bars['after call']
  end
end

它产生以下输出:

before call, foo1#bar is #<Method: Foo#bar>, foo2#bar is #<Method: Foo#bar>
after call, foo1#bar is #<Method: #<Foo:0x007fc0c3842ef8>.bar>, foo2#bar is #<Method: Foo#bar>

我在RSpec的github网站上报告了这个问题,并得到了确认/响应。

可以使用以下替代方法,这取决于最近引入的expect_any_instance_of方法。

class Roll
  def initialize
    install if !installed?
  end
  def install; puts 'install'; end
end
describe Roll do
  before do
    class RollTestClass < Roll; end
  end
  let(:roll_class) { RollTestClass }
  let(:roll) { RollTestClass.new }
  context 'when installed is true' do
    before do
      roll_class.any_instance.stub(:installed?).and_return(true)
    end
    it 'should not call install' do
      expect_any_instance_of(roll_class).to_not receive(:install)
      roll
    end
  end
  context 'when installed is false' do
    before do
      roll_class.any_instance.stub(:installed?).and_return(false)
    end
    it 'should call install' do
      expect_any_instance_of(roll_class).to receive(:install)
      roll
    end
  end
end

最新更新