47

在使用 RSpec 时,有什么方法可以删除任何存根和模拟吗?

例子:

RestClient.should_receive(:delete).with("http://www.example.com")
...
... 

# this will remove the mocking of "should_receive" and 
# restore the proper "delete" method on "RestClient".
RestClient.mocking_reset

mocking_reset是我对所需功能的虚构名称)。

我知道有一种方法“unstub”可以重置“stubs”而不是“should_receive”。

那么,除了“should_receive”之外,是否有任何等效于“unstub”的方法?

帕纳约蒂斯

4

3 回答 3

54

您可以通过以下方式覆盖一些以前的模拟:

expect(RestClient).to receive(:delete).and_call_original

或者,如果不是任何期望,只是一个简单的存根:

allow(RestClient).to receive(:delete).and_call_original

记住也存在expect_any_instance_ofallow_any_instance_of

于 2015-01-27T09:04:54.583 回答
32

目前(rspec-mocks 2.10.1)没有等效于unstub但 for的方法should_receive。您可以使用 重置所有存根和模拟rspec_reset,还可以编写肮脏的技巧来消除特定的期望(我不推荐)。

以下是删除对象上所有存根和期望的示例:

describe "resetting stubs and expectations with rspec_reset" do
  before do
    @person = mock('person')
    @person.should_receive(:poke)
  end

  it "should not fail when we reset all stubs and expectations" do
    @person.rspec_reset
  end
end

请注意,此方法在 rspec 源代码中注释为@private,这意味着您应该避免使用它而不是绝对必要的,并且它可能会在 rspec 的未来版本中中断而不会发出警告。然而,它在 rspec 本身的规范中被广泛使用,因此它似乎不太可能很快被弃用。

在深入研究 rspec-mocks 代码之后,您当然可以做一些非常讨厌的事情并自己撕掉一个特定的期望:

# Works in rspec 2.10.1
describe "removing an expectation with an ugly hack" do
  before do
    @person = mock('person')
    @person.should_receive(:poke)
  end

  it "should not fail after we hack rspec by violating every law of good programming, ever" do
    @person.instance_variable_get(:@mock_proxy).instance_variable_get(:@method_double)[:poke].clear
  end
end

这真的很糟糕,因为它违反了 rspec 测试包的封装,你不应该这样做。相反,如果您确实有一个令人信服的理由来消除特定的期望,那么正确的做法是在 rspec-mocks 的上游添加一个公共方法,该方法添加一个并行方法,unstub但用于消除特定的期望。它可能位于此处(请注意此文件中的stuband的定义unstub):

https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/methods.rb

在使用上述任何建议来消除期望之前,您可能需要考虑您的规范是否真的需要这样做,或者是否应该重构它们。Usingshould_receive是关于您的代码的断言,通常您应该尝试创建it只断言一件事的示例(即块)。我会很好奇为什么你需要类似的东西,rspec_reset除非你试图在全局设置中做太多事情(例如before :each或之前 :all 块),或者你的例子试图做太多事情(即使用多个断言在一个例子中)。

一个例外当然可能是在 rspec-mocks 的测试套件中,rspec_reset它用于在测试应用存根和模拟的功能的示例之间重置状态。除非您这样做,否则您的测试可能会得到改进,以不依赖于对象上存根和模拟的全局重置。

我希望这会有所帮助,如果您认为有一个合法的案例可以添加一个等效的方法,unstub但对于消息期望(即,在使用之后should_receive),我希望这会有所帮助。如果我确信这是一件可以做的事情,我会考虑添加此方法并建议将其添加到上游。也许它会被称为unset_expectation?也请随意使用上述代码和内部结构中的指南,自行组合 rspec-mocks 的拉取请求,我们将看看它是否被接受以创建等效于unstub.

于 2012-06-02T17:02:50.770 回答
13

对于RSpec >= 2.14,接受的答案将不再有效。

我向您推荐 Bernhard Köhler 在此线程上的回答(转载如下以防止链接腐烂):未定义的方法 `rspec_reset' with rspec version 2.14

RSpec 2.14 中不存在重置方法。相反,它是在 rspec-mocks 项目的 spec_helper.rb 文件中定义的辅助方法。

您可以使用以下方法取消expect/allow调用:

RSpec::Mocks.proxy_for(object).reset

对于RSpec 3.9.0,至少,我发现上面已经被替换为:

RSpec::Mocks.space.proxy_for(object).reset
于 2014-02-18T16:34:29.133 回答