Recently I needed to ‘unstub’ a method in Mocha. Browsing Mocha documentation and googling yielded no results. Apparently, Mocha doesn’t support a concept of ‘unstubbing’, i.e. recovering original implementation of a method that has been stubbed. After a little hacking, I found out that it’s quite easy (though not necessarily elegant) to call original implementation.
Let’s imagine we have a code like this:
class LolCatTest < Test::Unit::TestCase
def setup
LolCat.any_instance.stubs(:eat_cheeseburger).returns(nil)
end
def test_cheeseburger
kitteh = LolCat.new
assert_not_nil kitteh.eat_cheeseburger
end
end
We stubbed eat_cheeseburger method, because it performs some lengthy calculation or interacts with some external service and we normally don’t want it to be called in tests. But if there is some special test that has to call original implementation for some reason (like test_cheeseburger above), we need to resort to some hacking:
class LolCatTest < Test::Unit::TestCase
def setup
LolCat.send(:alias_method, :i_can_has_cheeseburger, :eat_cheeseburger)
LolCat.any_instance.stubs(:eat_cheeseburger).returns(nil)
end
def test_cheeseburger
kitteh = LolCat.new
kitteh.stubs(:eat_cheeseburger).returns(kitteh.i_can_has_cheeseburger)
assert_not_nil kitteh.eat_cheeseburger
end
end
There are two new elements in this example. First, before we stub eat_cheeseburger, we use alias_method to add a new name for this method. Second, we stub eat_cheeseburger to call the aliased method, thus bypassing the original stub.
If you know a better way to do this, I would be glad to hear about it. Or maybe there is some official way of unstubbing methods in Mocha, that I couldn’t find?
Add to:
digg
reddit
del.icio.us


February 10th, 2008 at 08:03:29
If the setup methods don’t apply to your test, then perhaps you need to create a new test file?
One of the cool things about the shoulda testing framework, is that you can have multiple context blocks each with their own setups, and can nest them. I think RSpec probably does the same thing. I imagine that you are using RSpec these days, from your more recent posts.
February 10th, 2008 at 11:28:32
David, that’s a good point, but sometimes you just have one test that won’t work with setup and a new file would be an overkill. And splitting test methods throughout many files makes it harder to find them.
But I think it should be possible to create many test classes in the same test file and that would also solve the problem. (Autotest would probably frown upon it, though.)
And yes, you’re right, RSpec’s and shoulda’s context blocks also solve it.
The example wasn’t meant to be realistic, only to illustrate what to do when you need to unstub something.
August 21st, 2009 at 17:57:02
I too was struggling with a way to unstub in mocha.
I found:
Mocha::Mockery.instance.stubba.unstub_all
and
Mocha::Mockery.instance.stubba.stubba_methods
on which you can do:
Mocha::Mockery.instance.stubba.stubba_methods.each do |meth|
if meth.stubbee == SomeClassOrInstanceIWantToUnstub && meth.method == “somemethodtounstub”
meth.unstub
end
end
March 7th, 2012 at 16:44:55
A bit late, but this functionality was added [1] to Mocha some time ago. Cheers, James.
[1] http://mocha.rubyforge.org/Mocha/Mock.html#method-i-unstub