Calling Base Methods When Mocking Abstract Classes With Moq

I use Moq. Mainly for its nice fluent API and because it allows you to not only mock interfaces but also abstract classes. I do have one problem with it though. Let me explain.

Mocking an abstract class basically works through dynamically creating a derived class wherein all virtual methods are overridden to create the behaviour specified by the Setup calls. If you don't set up anything for a method, you can let the mock object call the base method. This is done by setting the CallBase property to true.

But if you do set up any behaviour for a method, there is no way to let that method call the base implementation. Even if you only want to verify that the method gets called at all.

Thankfully Moq is open source. So we can stop whining and start modifying Moq. But how can this be implemented? And how can it be fit into the existing API?

Calling the Base Method

The first part is actually quite simple. For every method call that is set up, a MethodCall object is created. When the method of the mock object is called with matching arguments the call is rerouted through MethodCall.Execute(ICallContext). So we just need to add a callBase flag to MethodCall and within the Execute method invoke ICallContext.InvokeBase, if the flag is set.

public virtual void Execute(ICallContext call)
{
    ...

    if (this.callBase && !call.Method.IsAbstract)
    {
        call.InvokeBase();
    }

    ...
}

Integrating Into the Fluent Interface

To find an answer to the second question, we have to look at the existing fluent interface for setting up methods. Every behaviour specification starts with calling the Mock<T>.Setup method with the signature of the target method. The Setup method returns an interface that provides various methods for specifying the desired behaviour. As these methods return similar interfaces the methods can be chained after the Setup call.

Mock<Activator> mock = new Mock<Activator>();
mock.Setup(activator => activator.Activate())
    .Callback(() => Console.WriteLine("Activate was called."))
    .Returns(3);

Specification of the behaviour of the Activate method on a mock object of a hypothetical abstract Activator class.

Moq differentiates between void methods and method that return values. For the former Moq allows you to specify the return value using the Returns method in the method chain. For the latter this option is not available. The following method chains are possible (a the chain may stop after any method).


Method chains for void methods.

Available method chains for setting up behaviour on void methods.


Method chains for non-void methods.

Available method chains for setting up behaviour on non-void methods.

What I want to have is a CallBase method as part of the method chain to specify that the base implementation of the method should be called on the mock object.

Mock<Activator> mock = new Mock<Activator>();
mock.Setup(activator => activator.Activate())
    .CallBase()
    .Callback(() => Console.WriteLine("Activate was called."))
    .Returns(3);

Usage of the CallBase method in the mock behaviour specification for Activate.

It seems reasonable to place the CallBase method before the Throws, Raises and Returns methods in the method chain as those methods basically set up the finishing behaviour of a method. For non-void methods the Moq API already offers two separate callbacks, one before and one after Returns. So instead of having to decide where CallBase should be placed in respect to the first Callback, it would be nice to also have separate callbacks before and after CallBase.


Method chains for void methods with CallBase additions.

Additions of the Moq API with CallBase for setting up behaviour on void methods. For non-void methods an analogous enhancement is used.

New Interfaces

Internally all the interfaces defining the method chains are implemented by MethodCall. An object of this class is created in the Setup method and then passed from method to method. So to add new methods to the methods chain, we just have to define new interfaces and add implementations of these interfaces to MethodCall

Therefore we need to introduce two new interfaces, which I called ICallBase and ICallbackCallBase for the lack of better names. The ICallbackCallBase interface realizes the new first Callback method. This Callback method returns an ICallBase interface, which declares the CallBase method. By inheriting from other interfaces these interfaces enable omitting parts of the method chain.

For simplicity I'll only list the interfaces for void methods. For non-void methods these get slightly more complicated as the return value type has to be carried around in a generic parameter to make sure that the Returns method has the correct signature.

public interface ICallbackCallBase
{
    ICallBase Callback(Action action);
    ICallBase Callback<T>(Action<T> action);
    ICallBase Callback<T1, T2>(Action<T1, T2> action);
    ICallBase Callback<T1, T2, T3>(Action<T1, T2, T3> action);
    ...
}

public interface ICallBase : ICallbackResult
{
    ICallBaseResult CallBase();
}

public interface ICallBaseResult : ICallback, ICallbackResult
{
}

In addition to the new interfaces, the ISetup interface, that is returned by the Setup method, has to be modified to allow the method chain path to the CallBase method.

public interface ISetup<TMock> : ICallbackCallBase, ICallBase, ICallbackResult,
    IRaise<TMock>, IVerifies
    where TMock : class
{
}

Changes in MethodCall

As mentioned earlier, the MethodCall class needs to implement the two newly created interfaces. The implementation of the ICallBase interface in MethodCall simply sets the callBase that is evaluated in the Execute method as described earlier.

private bool callBase;

public ICallBaseResult CallBase()
{
    this.callBase = true;
    return this;
}

Implementation of the ICallBase interface in MethodCall.

Implementing the ICallbackCallBase interface is a bit trickier. But we can build upon the implementation of the other CallBase methods in MethodCall. These other CallBase methods force us to use explicit interface definitions for implementing the ICallbackCallBase.Callback method. Otherwise we'd have a name clash. Luckily, as MethodCall is an internal object and only referenced via the interfaces, this doesn't matter.

private Action<object[]> afterCallBaseCallback;

ICallBase ICallbackCallBase.Callback(Action callback)
{
    SetCallbackWithoutArguments(callback);
    return this;
}

ICallBase ICallbackCallBase.Callback<T>(Action<T> callback)
{
    SetCallbackWithArguments(callback);
    return this;
}

ICallBase ICallbackCallBase.Callback<T1, T2>(Action<T1, T2> callback)
{
    SetCallbackWithArguments(callback);
    return this;
}

ICallBase ICallbackCallBase.Callback<T1, T2, T3>(Action<T1, T2, T3> callback)
{
    SetCallbackWithArguments(callback);
    return this;
}

...

Implementation of the ICallbackCallBase interface in MethodCall.

As you see the Callback methods make use of the private SetCallbackWithArguments and SetCallbackWithoutArguments methods. In their original form these method only set the setupCallback. They have to be modified to set the new afterCallBaseCallback if the callBase flag is set. Therefore each occurrence of

this.setupCallback = delegate(object[] args) { callback.InvokePreserveStack(args); };

has to be replaced with

if (this.callBase)
{
    this.afterCallBaseCallback =
        delegate(object[] args) { callback.InvokePreserveStack(args); };
}
else
{
    this.setupCallback =
        delegate(object[] args) { callback.InvokePreserveStack(args); };
}

Now returning to the Execute method, we have to add the call to the afterCallBaseCallback. The calls to ICallContext.InvokeBase and afterCallBaseCallback will be inserted into the Execute method after the invocation of setupCallback.

public virtual void Execute(ICallContext call)
{
    ...

    if (setupCallback != null)
    {
        setupCallback(call.Arguments);
    }

    if (this.callBase && !call.Method.IsAbstract)
    {
        call.InvokeBase();
    }

    if (afterCallBaseCallback != null)
    {
        afterCallBaseCallback(call.Arguments);
    }

    ...
}

And that's it. Granted this is not particularly simple or easy and I really would like to provide a nice download to somehow incorporate into your projects, but I couldn't think of a way to write this as an extension to Moq. You have to modify MethodCall which is an internal class. Even deriving from MethodCall is not an option as you cannot simply replace the MethodCall objects that are created and registered in the Setup method with new derived objects.

And because this obviously isn't a finished solution I didn't care about implementing CallBase for SetupGet or SetupSet for the simple reason, that I didn't need it yet.

Author
Tags

0 Responses