Creating a single mock that mocks multiple interfaces?

646 views
Skip to first unread message

Royston Shufflebotham

unread,
May 29, 2006, 5:34:49 AM5/29/06
to RhinoMocks digest subscribers
Hi there,

I was wondering if it's possible to create a single mock object that
mocks multiple interfaces?

For example, I'd like a mock object that implemented both IFoo and
IEquatable<IFoo> (a fairly standard pattern in .NET 2). I could create
a new interface IEquatableFoo that extended both IFoo and
IEquatable<IFoo>, and then mock that, but that seems to be missing the
point of mocking somewhat.

(Of course the maximum extension of this would be to be able to create a
mock that extended a single type and implemented multiple interfaces,
but I don't need that right now... ;-) )

Any thoughts?

Cheers,
Royston.

Ayende Rahien

unread,
May 29, 2006, 6:14:08 AM5/29/06
to Rhino...@googlegroups.com
At the moment, you can't do this.
In general, I don't think that you would need this often, although I can think of several scenarios where this would be applicable.

 

blaz

unread,
May 29, 2006, 6:46:54 AM5/29/06
to Rhino.Mocks
I'm not sure what you ment with your remeak ...

> (Of course the maximum extension of this would be to be able to create a
> mock that extended a single type and implemented multiple interfaces,
> but I don't need that right now... ;-) )

Anyway, you can implement abstract class that implements any number of
interfaces (all methods abstract) and then mock this class.

Royston Shufflebotham

unread,
May 29, 2006, 8:52:28 AM5/29/06
to Rhino...@googlegroups.com
I just meant that the ultimate extension of this ability would be the
ability to mock a single class and multiple instances in one go.

e.g. object o = mocks.CreateMultipleMock( typeof(BaseClass), new Type[]
{ typeof(Interface1), typeof(Interface2) }, args );

Without this, you have to write this class:

abstract class MyDummyClass : BaseClass, Interface1, Interface2
{
// Need to explicitly declare all the interface methods abstract
public abstract Interface1.Method1();
public abstract Interface1.Method2();
public abstract Interface1.Method3();
...

// Need to explicitly declare all the interface methods abstract
public abstract Interface2.Method1();
public abstract Interface2.Method2();
public abstract Interface2.Method3();
...
}
object o = mocks.CreateMock( typeof(MyDummyClass), args );

Doable, but a pain!

Royston.

David Chelimsky

unread,
May 29, 2006, 9:20:55 AM5/29/06
to Rhino...@googlegroups.com
On 5/29/06, Royston Shufflebotham <roy...@shufflebotham.org> wrote:
>
> I just meant that the ultimate extension of this ability would be the
> ability to mock a single class and multiple instances in one go.
>
> e.g. object o = mocks.CreateMultipleMock( typeof(BaseClass), new Type[]
> { typeof(Interface1), typeof(Interface2) }, args );
>
> Without this, you have to write this class:
>
> abstract class MyDummyClass : BaseClass, Interface1, Interface2
> {
> // Need to explicitly declare all the interface methods abstract
> public abstract Interface1.Method1();
> public abstract Interface1.Method2();
> public abstract Interface1.Method3();
> ...
>
> // Need to explicitly declare all the interface methods abstract
> public abstract Interface2.Method1();
> public abstract Interface2.Method2();
> public abstract Interface2.Method3();
> ...
> }
> object o = mocks.CreateMock( typeof(MyDummyClass), args );
>
> Doable, but a pain!

Can you write out an example of a testcase that would use such a mock?

Royston Shufflebotham

unread,
May 30, 2006, 5:05:17 AM5/30/06
to Rhino...@googlegroups.com
Yep, sure I can give a test case. There are lots of examples.

This need arises whenever you have a method that tests to see if an
object implements a particular interface at runtime, and performs some
behaviour if it does. Often we mock things of a class or interface type
T because we need to pass it into a method that takes a T, but if that
method also does something different if the object also implements X or
Y, that's where you need multi-type mocking.

You get a lot of this in the .NET ComponentModel framework with
interfaces like ISupportInitialize or IRaiseItemChangedEvents. Methods
take objects of type Control or Container and then do extra work if
those objects implement those two interfaces.

But for a concrete example one has actually just turned up in the other
email thread I started where I've been discussing mocking the Equals
method on object. In that case, I have a method that takes an object of
type Foo and tests to see if the object also implements
IEquatable<IBar>; if it does, IEquatable<IBar>.Equals(IBar) will be
called on that object, possibly directly, possibly via another method.
It should not be calling Object.Equals(Object) in case the Foo author
(which isn't me) has implemented IEquatable<IBar>.Equals(IBar)
differently from Object.Equals(Object). (In particular the former may
be a faster implementation.)

So I'd like to write:

MockRepository mocks = new MockRepository();
Foo foo = mocks.DynamicMultiMock<Foo>( new Type[] {
typeof(IEquatable<IBar>) } );
// Check that Object.Equals is not called
Expect.Call( foo.Equals(foo) ).IgnoreArguments().Repeat.Never();
// Check that IEquatable<IBar> is called
IEquatable<IBar> fooAsIEquatable = (IEquatable<IBar>)foo;
Expect.Call( fooAsIEquatable.Equals( (IBar)null ) ).IgnoreArguments();
mocks.ReplayAll();
foo.FooMethod();
mocks.VerifyAll();

To do this at the moment I'd have to make a new class manually, that
extended Foo, and also implemented IBar and IEquatable<IBar>; that class
would need to provide explicit abstract stub methods for all methods in
those interfaces.

Another concrete example I have is of a factory interface. I have an
IFoo interface and an IFactory<IFoo> interface in my API; often people
will implement these interfaces using different types, but it should be
possible for somebody to implement both interfaces on the same class
(and hence the same object) if they like. I want to assert that I've
not done anything in my code that assumes that the two are different
objects (e.g. putting them into the same hashtable or something like
that), so it would be nice to mock up an object that does implement both
interfaces and set up the IFactory<IFoo>.CreateInstance() method to
return the object itself.


Without multi-type mocking I'd have to define a new interface
[IFooAndFactory : IFoo, IFactory<Foo>] and mock that. That's fine as a
workaround but if you need to bring classes into the problem it gets
messy as you need to define lots of new abstract methods on the class.

[Looking at the APIs for DynamicProxy, it looks like it already has
support for producing a proxy that extends a class and implements
multiple interfaces. Indeed RhinoMocks uses that API and inserts one of
its own interfaces into the list of interfaces that will be supported by
the proxy.]

Cheers,
Royston.

Ayende Rahien

unread,
May 30, 2006, 9:48:27 AM5/30/06
to Rhino...@googlegroups.com
This is indeed possible, and you present a compelling case.
I'll pkay around with this, seeing if this is workable.
You already know that I'm accepting patches :-)

 
Reply all
Reply to author
Forward
0 new messages