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


4 responses to “Unstubbing methods in Mocha

  • David Lowenfels

    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.

  • szeryf

    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.

  • Jacob

    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

  • floehopper

    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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: