Unstubbing methods in Mocha

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! digg blog_head.png reddit delicioussmall.gif del.icio.us

~ by szeryf on 2007-11-09.

3 Responses to “Unstubbing methods in Mocha”

  1. 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.

  2. 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.

  3. 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

Leave a Reply