Saturday, February 02, 2008
Testing: Mocha's stub_everything method
The Mocha mocking framework provides a method, stub_everything, that returns an object that will respond 'nil' to any message sent to it. The stub_everything method is indispensable for creating an object that is needed for testing, but the interactions are completely unimportant.
For example, in the following test the ReservationService::reserve_for method needs to return a duck that responds to the same methods that are defined on the (not shown) Reservation class. However, the focus of the test has nothing to do with the behavior of the reservation duck, so stub_everything is the perfect duck because it requires no additional set up and responds to all the methods required without error.
The stub_everything method is also nice because it can take parameters. For example you may want to test that the book_for method returns a confirmation number. The following test specifies the value of the confirmation_number value, but it uses stub_everything so that each other method call will return nil (without causing an error).
Another usage of stub_everything that might not be immediately apparent is that it can be used as both a stub and a mock. The following test creates a stub and then sets an expectation on it. As a result, the expectation is verified (which is the focus of the test) and all other calls to the same object simply do nothing.
Using the stub_everything method of mocha can remove noise from tests and also make them more robust by ignoring all messages that are unimportant to the current test.
For example, in the following test the ReservationService::reserve_for method needs to return a duck that responds to the same methods that are defined on the (not shown) Reservation class. However, the focus of the test has nothing to do with the behavior of the reservation duck, so stub_everything is the perfect duck because it requires no additional set up and responds to all the methods required without error.
# implementation
end
# implementation
end
# implementation
end
reservation = ReservationService.reserve_for(customer, self)
MaidService.notify(reservation) if reservation.tomorrow?
VipService.notify(reservation) if reservation.for_vip?
reservation.confirmation_number
end
end
room = HotelRoom.new
ReservationService.expects(:reserve_for).with(:customer, room).returns(stub_everything)
room.book_for(:customer)
end
endThe stub_everything method is also nice because it can take parameters. For example you may want to test that the book_for method returns a confirmation number. The following test specifies the value of the confirmation_number value, but it uses stub_everything so that each other method call will return nil (without causing an error).
# implementation
end
# implementation
end
# implementation
end
reservation = ReservationService.reserve_for(customer, self)
MaidService.notify(reservation) if reservation.tomorrow?
VipService.notify(reservation) if reservation.for_vip?
reservation.confirmation_number
end
end
reservation = stub_everything(:confirmation_number => "confirmation number")
ReservationService.stubs(:reserve_for).returns(reservation)
assert_equal "confirmation number", HotelRoom.new.book_for(:customer)
end
endAnother usage of stub_everything that might not be immediately apparent is that it can be used as both a stub and a mock. The following test creates a stub and then sets an expectation on it. As a result, the expectation is verified (which is the focus of the test) and all other calls to the same object simply do nothing.
hotel = stub_everything
hotel.expects(:name=).with "Marriott"
Hotel.stubs(:new).returns hotel
Hotel.parse("Marriott||")
end
end
hotel = self.new
hotel.name, hotel.location, hotel.capacity = attributes.split("|")
hotel
end
endUsing the stub_everything method of mocha can remove noise from tests and also make them more robust by ignoring all messages that are unimportant to the current test.
Labels: mocha, stub, testing, Testing Refactorings
Comments:
<< Home
Nice post Jay. I was actually wishing for something like this recently, as I'd have lots of lines that were just
a.stubs(:method)
obviously not caring about its return value. This will clean things up nicely. Another great example of how its usually worth learning as much as you can about library rather than only a few of its methods.
a.stubs(:method)
obviously not caring about its return value. This will clean things up nicely. Another great example of how its usually worth learning as much as you can about library rather than only a few of its methods.
My favorite from-scratch implementation of stub_everything...
class Sponge
def method_missing(*args)
self
end
end
#:-)
Post a Comment
class Sponge
def method_missing(*args)
self
end
end
#:-)
<< Home



