简体   繁体   English

用RSpec发出问题

[英]Issue stubbing with RSpec

I am trying to understand why the result of these tests, the first test claims the method is not stubbed, however, the 2nd one is. 我试图理解为什么这些测试的结果,第一个测试声称该方法不是存根,但是,第二个是。

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

It's also strange the error says expected to have received install , but I think that is likely just faulty feedback from the RSpec DSL. 同样奇怪的是错误说expected to have received install ,但我认为这可能只是来自RSpec DSL的错误反馈。 But maybe worth noting. 但也许值得注意。

  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.

The "spy pattern" of RSpec requires that the objects have been previously stubbed. RSpec的“间谍模式”要求对象先前已被存根。 However, any_instance.stub doesn't actually stub the methods "for real" unless/until the method is invoked on a particular object. 但是, any_instance.stub实际上不会将方法“for real”存根,除非/直到在特定对象上调用该方法。 As such, the methods appears as being "unstubbed" and you get the error you're getting. 因此,这些方法显示为“未被取消”,您将收到错误。 Here's some code that demonstrates the change in definition: 以下是一些演示定义更改的代码:

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

which produces the following output: 产生以下输出:

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>

I reported this an issue on RSpec's github site and got this acknowledgement/response . 我在RSpec的github网站上报告了这个问题,得到了这个确认/回复

You can use the following alternative approach, which depends on the recently introduced expect_any_instance_of method. 可以使用以下替代方法,该方法取决于最近引入的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

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

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