[mocha-developer] mocking missing methods

Dan North dan at tastapod.com
Tue May 1 18:28:56 EDT 2007


James Mead wrote:
> Wow - it's great to have so much input on this...
It's obviously something we've all been thinking about :)
> I really like "quacks_like". :-)
>   
So that's three for three... hmm!
> I'm not clear why you would want to be able to do this if Sheep & Ninja are
> distinct classes.
Think of a class/module definition describing a role (an aspect of 
behaviour). Say in your production code, you have a Shop object 
providing a bunch of services. You might want to use it as a 
RetailOpportunity, a DeliveryDestination, a ShopliftingVenue or any 
number of other expressively-named roles. These might well be 
implemented as mixins - the shop would "quack like a" delivery 
destination if you were a courier - and you want to test that behaviour.

So you need a way of saying "I want to mock this module" (or more 
accurately "I want to mock something in the role described by this 
module"). Now either a) mocha takes the module/class name, and needs to 
"construct" an instance of the module, say using Object.new.extend(mod) 
or class constructor, or the user has to provide an object that includes 
the module, which pushes the onus onto the user (and by implication adds 
noise in the test).

In the former case, you get the examples I suggested, and mocha has to 
do more work. In the latter case, mocha would take a ready-made 
instance,  which means the user - and therefore the test - would have to 
do more stuff to express its intent.
>  If the Sheep class includes Enumerable at class
> definition time, any Sheep instance will respond_to? Enumerable methods.
>   
Right, but what if I don't care about whether or not it's a Sheep? Just 
that right now it's being Enumerable?
> However, it would be nice to have a solution that covers extending a Sheep
> instance at runtime. I'm not so sure that there is anything wrong with your
> "yuk" example given that it is a bit of an edge case.
>   
I respectfully disagree. If you are using mocking to express 
interactions between roles, then this will be very much the norm.
> One thing I don't think I explained about my equivalent of
> "responds_like_type" i.e. "responds_like(instance_of(Sheep))" was that it
> would use a sneaky trick to construct an instance of the class without
> calling initialize purely in order to be able to use "respond_to?" instead
> of "instance_method"...
>   
That'd work (unless the class defines methods or extends itself in its 
constructor, in which case all bets are off anyway!). In 
statically-typed languages the convention is to mock roles rather than 
classes (hence the focus on interfaces as roles). In a dynamic language 
things are a bit squishier. Mocking modules (with Object.new.extend(mod) 
and classes (by bypassing the constructor) seems like a pretty solid 
approach, and is more expressive than just mock().

My original use case was for the mock to fail with an undefined method 
error if I called a method that didn't exist in the mocked type, and 
this will give me that and more besides, so I'm happy :)

> I think I'd prefer to use "respond_to?" in this way in the underlying
> implementation of "responds_like_type". As I've said the "respond_to?"
> method feels like the correct method to use in all circumstances.
>   
I agree that a well-implemented object should respond_to? the right things.

Anyway, thanks for listening. Mocha is looking great James, and I'll 
happily fall in line with whatever you decide.

Cheers,
Dan


More information about the mocha-developer mailing list