In RSpec, is there a method equivalent to "unstub" but for "should_receive"?
mocking, rspec, stub
Solution
At the moment (rspec-mocks 2.10.1) there is not a method equivalent to `unstub` but for `should_receive`. You can reset all stubs and mocks using `rspec_reset`, and you can also write dirty hacks to remove a particular expectation (which I wouldn't recommend).
The following is an example of removing all stubs and expectations on an object:
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
Note that this method is annotated in the rspec source code as `@private`, which means that you should avoid using it more than absolutely necessary and it may break in future versions of rspec without warning. It is, however, pretty widely used in the specs for rspec itself, so it seems less likely that this will be deprecated any time soon.
After digging through the rspec-mocks code a bit more, you can of course do something really nasty and tear out the one specific expectation yourself:
# 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
This is really bad since it violates the encapsulation of the rspec test package and you shouldn't do it. Instead, if you really had a compelling reason to remove a particular expectation, the right thing to do would be to add a public method upstream in rspec-mocks that adds a parallel method to `unstub` but for removing specific expectations. It would probably be located here (note the definition of `stub` and `unstub` as well in this file):
https://github.com/rspec/rspec-mocks/blob/master/lib/rspec/mocks/methods.rb
Before going out and using any of the suggestions above for removing the expectation you may want to consider if your specs really need to do this or if they should be refactored. Using `should_receive` is an assertion about your code, and usually you should try to create examples (ie `it` blocks) that only assert one thing. I would be very curious about why you're needing something like `rspec_reset` unless you're trying to do too much in global setup (eg `before :each` or before :all blocks), or if your examples are trying to do too much (ie. with multiple assertions in a single example).
The one exception to this may of course be in the test suite of rspec-mocks, where `rspec_reset` is used to reset state between examples that test the functionality of applying stubs and mocks. Unless you're doing that, chances are your tests could be improved to not rely on global resets of stubs and mocks on an object.
I hope that this helps and please do let me know if you think that there is a legitimate case for adding an equivalent method to `unstub` but for message expectations (ie., after using `should_receive`). If I'm convinced that this is an OK thing to do I would consider adding this method and proposing it to be added upstream. Maybe it would be called `unset_expectation`? Please also feel free to use the guidance into the code and internal structures above to put together a pull request for rspec-mocks on your own, and we'll see if it gets accepted to create a mocking equivalent to `unstub`.
Problem
Is there any method to remove any stubbing and mocking while using RSpec? Example: ``` 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` is my ficticious name for the required functionality). I know that there is the method "unstub" which resets "stubs" but not "should_receive"s. So, is there any method equivalent to "unstub" but for "should_receive"? Panayotis