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.
> (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.
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.
Can you write out an example of a testcase that would use such a mock?
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.