在RSpec中,是否有一种方法相当于"unstub"而是"should_receive"?

p.m*_*los 38 rspec mocking stub

在使用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
Run Code Online (Sandbox Code Playgroud)

(mocking_reset是我所需功能的虚构名称).

我知道有一种方法"unstub"可以重置"stubs"而不是"should_receive".

那么,有没有任何方法相当于"unstub"而是"should_receive"?

Panayotis

Wai*_*... 43

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

expect(RestClient).to receive(:delete).and_call_original
Run Code Online (Sandbox Code Playgroud)

或者,如果没有任何期望,只需一个简单的存根:

allow(RestClient).to receive(:delete).and_call_original
Run Code Online (Sandbox Code Playgroud)

记住还存在expect_any_instance_ofallow_any_instance_of.

  • 这并不等同于“unstub”,因为它继续观察对模拟方法的调用。 (2认同)

Jus*_*geb 30

目前(rspec-mocks 2.10.1)没有一种方法等同unstubshould_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
Run Code Online (Sandbox Code Playgroud)

请注意,此方法在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
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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


Jel*_*Cat 10

对于RSpec> = 2.14,接受的答案将不再有效.我推荐你到BernhardKöhler在这个帖子上的答案(转载如下以防止链接腐烂):未定义的方法`rspec_reset'与rspec版本2.14

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

module VerifyAndResetHelpers
  def verify(object)
    RSpec::Mocks.proxy_for(object).verify
  end

  def reset(object)
    RSpec::Mocks.proxy_for(object).reset
  end
end
Run Code Online (Sandbox Code Playgroud)

您可以看到此方法将重置操作委托给底层代理,而不是将其添加到相关对象的类定义中.