【问题标题】:Rspec Double leaking to another exampleRspec Double 泄漏到另一个例子
【发布时间】:2021-03-24 08:23:26
【问题描述】:

我正在测试一个使用发出外部请求的客户端的类,我想模拟这个客户端,但要验证它是否被调用,但是我遇到了双重错误。

我的测试看起来像这样:

  describe '#execute' do
    let(:attributes) { {foo: 'bar'} }
    let(:client_double) { double('client', create: nil) }
    let(:use_case) { described.class.new }

    before do
      allow(Client::Base).to receive(:new).and_return(client_double)
      use_case.execute(attributes)
    end

    it 'creates something' do
      expect(Something.find_by(foo: 'bar')).not_to be_nil
    end

    it 'calls client' do
      expect(client).to have_received(:create).with('bar')
    end
  end

第一个示例按预期通过,但是 rspec 在第二个示例中不断中断,给我这个错误:

#<Double "foo"> was originally created in one example but has leaked into another example and can no longer be used. rspec-mocks' doubles are designed to only last for one example, and you need to create a new one in each example you wish to use it for.

有人知道我能做些什么来修复它吗?

【问题讨论】:

    标签: ruby rspec


    【解决方案1】:

    通过 Let 方法重用夹具

    在这种情况下,before 实际上是before(:each),它重用了您使用#let 辅助方法定义的client_double属性let 命令使这些变量在功能上等同于所描述对象范围内的实例变量,因此您并没有真正在每个示例中测试新创建的对象。

    一些替代方案包括:

    1. 重构以将您的所有设置放入 before(:each) 而不使用 let 语句。
    2. 通过在每个示例中进行更多设置来使您的测试 DAMP。
    3. 为新的#describe 设置新范围,这样您的测试替身/值就不会被重复使用。
    4. 如果需要,使用 :before、:after 或 :around 块在测试之间重置状态。

    由于您没有展示实际的类或实际的测试代码,因此很难就测试您要测试的对象的正确方法提供具体的见解。甚至不清楚为什么您觉得需要在单元测试中测试合作者对象,因此您可能也需要考虑一下。

    【讨论】:

    • 感谢 Todd 提供了非常好的答案,但事实证明这是因为客户是单身人士,我还没有注意到......所以我没有模拟 :new 方法,而是模拟了:实例方法,一切正常。
    【解决方案2】:

    原来我使用的是单例作为客户端,之前没有意识到,所以它是通过示例缓存它的真正的类。为了解决这个问题,我所做的只是模拟 instantiate 方法而不是 new 方法,一切正常。

    所以这最终奏效了:

    allow(Client::Base).to receive(:instantiate).and_return(client_double)
    

    【讨论】:

      猜你喜欢
      • 2015-06-23
      • 1970-01-01
      • 1970-01-01
      • 2011-11-12
      • 1970-01-01
      • 2010-11-28
      • 2012-02-01
      • 2011-09-25
      • 1970-01-01
      相关资源
      最近更新 更多