【问题标题】:Issue stubbing with RSpec使用 RSpec 进行问题存根
【发布时间】:2013-11-22 19:00:07
【问题描述】:

我试图理解为什么这些测试的结果,第一个测试声称该方法没有被存根,但是,第二个是。

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.

【问题讨论】:

    标签: ruby rspec stub


    【解决方案1】:

    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 网站上报告了这个问题并得到了this acknowledgement/response

    可以使用以下替代方法,这取决于最近引入的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
    

    【讨论】:

    • 太棒了!我决定在 S.O. 上发帖。而不是在 rspec-mocks github 问题中,因为我认为我在做一些非常规或不正确的事情。很高兴知道它是一个 rspec 问题。 expect_any_instance_of 策略有点尴尬,但必须这样做。谢谢!
    • 快速附录:如果您使用 Mocha 进行模拟,则在使用 any_instance 时它会“实际上”取消调用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-14
    • 2015-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多