Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Partial Mock Object or mocking an instance of an object. (See related posts)

From: http://www.karmiccoding.com/articles/2006/03/11/under-the-hood-with-ruby-partial-mock-objects-for-unit-testing

"What happens though, if you want to override a class in an instance of an object, and not all of its kind? Typically you would define a mock object, and create an instance of it. But, in Ruby there is an easier and faster way that doesn’t involve writing a different mock class for each different scenario – and it is made possible by the singleton class. This clever bit of ruby hackery lets you override the behaviour of a single instance of a class, creating what I’ve decided to call a partial mock object. To demonstrate, I’ve written a small method called override_method which will override the behaviour of the specified method in the passed object, like so:

# Overrides the method +method_name+ in +obj+ with the passed block
def override_method(obj, method_name, &block)
  # Get the singleton class/eigenclass for 'obj'
  klass = class <<obj; self; end 

  # Undefine the old method (using 'send' since 'undef_method' is protected)
  klass.send(:undef_method, method_name)

  # Create the new method
  klass.send(:define_method, method_name, block)
end

# Just an example class
class Foo 
  def do_stuff
    "I'm okay!" 
  end
end

# Test code
list = []
5.times { list.push(Foo.new) }

# We override the method here!
override_method(list.first, :do_stuff) { "I'm NOT okay!" }

list.each_with_index { |f, i| puts "(#{i}) #{f.do_stuff}" }

Outputs:
(0) I'm NOT okay!
(1) I'm okay!
(2) I'm okay!
(3) I'm okay!
(4) I'm okay!

As you can see, only the first object in the array’s behaviour has been changed – the rest have remained untouched. Because of this, you can embed these partial dynamic mock objects deeply into your code without the need to specially instantiate a mock object deep in your code, or writing a ‘clever mock’ to only trigger the determined behaviour in certain objects.

Where this code comes in really handy is when you need an object to raise a difficult to simulate exception (like a disk full error) on a certain method to test your error handling – simply call override_method and pass in a call to raise and voila! Dynamic partial mock objects on the fly!"

Comments on this post

floehopper posts on Aug 26, 2006 at 14:29
It was doing things like this that led us to develop Mocha (http://mocha.rubyforge.org) which allows you mock or stub methods on concrete objects or classes. In your example, instead of...

override_method(list.first, :do_stuff) { "I'm NOT okay!" }

... you would write ...

list.first.stubs(:do_stuff).returns("I'm NOT okay!")

Where Mocha really comes into its own is doing this for classes e.g.

Foo.stubs(:create).returns(mock_foo)

In this case Mocha puts the class back together at the end of each test method, so other tests will be unaffected.

You need to create an account or log in to post comments to this site.


Click here to browse all 4860 code snippets

Related Posts