[mocha-developer] mocking missing methods

James Mead jamesmead44 at gmail.com
Tue May 1 08:58:05 EDT 2007

Wow - it's great to have so much input on this...

On 30/04/07, Dan North <dan at tastapod.com> wrote:> This is timely for me.
I've been thinking about exactly this vocabulary
> recently, but in the context of BDD rather than (as well as?) mocking.
> It's about the terms "is a" and "has a" and how they restrict your
> thinking because they don't really cover the idea of roles. You need
> "acts like a" or "behaves like a" to really describe multiple hats.
> In this instance, I would like something like "acts like a" (in fact,
> David and I were discussing "quacks_like" in another conversation).

I really like "quacks_like". :-)

> Here's some thinking-out-loud:
> So:
>    mock_sheep.responds_like(Sheep.new)
> or
>    mock_sheep.acts_like(Sheep.new)
> This should be additive:
>    mock_ninja_sheep.acts_like(Sheep.new)
>    mock_ninja_sheep.acts_like(Ninja.new)
> or even:
>    mock_ninja_sheep.acts_like(Sheep.new, Ninja.new)

I'm not clear why you would want to be able to do this if Sheep & Ninja are
distinct classes.

> One problem I see is a hard-to-detect semantic error:
>    mock_sheep.acts_like(Sheep) # oops - meant Sheep.new


> Also, what about modules? This is fugly:
>    mock_countable_sheep.acts_like(Sheep.new.extend(Enumerable)) # yuk

A good point, but this would only be an issue if you were extending a Sheep
instance at runtime. If the Sheep class includes Enumerable at class
definition time, any Sheep instance will respond_to? Enumerable methods.
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.

> So, we need a way of saying: "fail intuitively if the mocked object
> wouldn't respond to this call".
> Ok, end of ramble. Here's my ill-thought-out proposal:
> mock_sheep = mock("sheep")                    # give it a name
> mock_sheep.responds_like_type(Sheep, ...)     # uses #instance_method
> mock_sheep.responds_like_instance(ninja, ...) # uses #respond_to?
> mock_sheep.responds_like(cheese)              # depends if cheese is

I like this.

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

def instance_of(klass)
  class_without_initialize = Class.new(klass) do
    def initialize(*args)
      # intentionally left blank

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.

> The responds_like_type version could even check if type implements
> method_missing.

As I've mentioned before, I think that "respond_to?" implementations are
supposed to match up with "method_missing" implementations. So as long as we
use "respond_to?" in the underlying implementation, I don't think we need to
check for the existence of "method_missing". Does anybody know if I'm
talking rubbish about this convention/contract.

> The failure mode here would be if you wanted to mock the /instance/
> methods of a /class/, using responds_like(type), but that seems very
> much like an edge case, and you could explicitly use
> responds_like_instance(type) anyway.
> Of course, all these checks would be done at method invocation time, so
> late binding would work.



More information about the mocha-developer mailing list