The TestControllerBuilder in MVCContrib’s TestHelper library has a hard dependency on Rhino Mocks.  I’m not a big fan of Rhino Mocks, I prefer to use Moq, and while it’s not a big deal to reference two separate mocking libraries, I’d rather just have one mocking library in my project.  I’m working on a patch to address this open workitem in MVCContrib.  I don’t want to create a hard reference to Moq, so that means I have to access Moq, and all it’s generic types and methods, using reflection.  This post presents my Moq proxy class, based on a similar idea from StructureMap’s auto-mocking container.

The TestControllerBuilder in MVCContrib.TestHelper is a handy class for attaching mocks to an MVC Controller class to facilitate testing.  Unfortunately, it uses Rhino Mocks, which means you must include Rhino Mocks in your projects in order to leverage it.  My test projects already reference Moq (my preferred testing framework), and I don’t like the idea of carrying around two libraries that provide the same capabilities.  I’m not the only one, as there has been an open work item to address this issue for quite some time now. One of the nice things about Open-Source Software is that instead of wasting energy complaining about something, I can try to fix it. 

I have three main goals for the fix.  First, it should not be a breaking change.  Existing consumers of the API should be unaffected.  Second, it should not create a hard reference between MVCContrib and Moq.  MVCContrib is already using Rhino Mocks for its own testing, and I’m trying to remove the need for referencing two mocking frameworks in my own projects, so it would be a bit ironic if I required MVCContrib to pick up a dependency on Moq.  Finally, I want it to be very simple to swap out the mocking library; in fact, I’d like it to automatically use whichever library is available.  I’d even like it to be pluggable so that a different mocking library could be plugged in if desired.

I’m not 100% tied to this approach yet (I’m still thinking of this more as a spike for now), but I’m using the strategy pattern to decouple TestControllerBuilder from the mocking library.  There are other places in MVCContrib’s TestHelper library that are doing mocking, so I will probably change my approach, but this worked well as a proof-of-concept.  TestControllerBuilder now accepts an IControllerBuilderStrategy that handles the actual mocking and any other library-specific setup.  The interface is quite simple:

public interface IControllerBuilderStrategy 
{
    void Setup(TestControllerBuilder testControllerBuilder);
}

By default, TestControllerBuilder uses the RhinoMocksControllerBuilder (this satisfies my first goal: existing consumers of the API will get the exact same behavior as before).  Because MVCContrib.TestHelper has a direct dependency on Rhino Mocks, RhinoMocksControllerBuilder is a straight-forward refactoring of TestControllerBuilder’s mock-dependent logic into a new class:

public class RhinoMocksControllerBuilder : IControllerBuilderStrategy 
{
    protected MockRepository _mocks = new MockRepository();

    public void Setup(TestControllerBuilder testControllerBuilder)
    {
        var httpContext = _mocks.DynamicMock<HttpContextBase>();

        var request = _mocks.DynamicMock<HttpRequestBase>();
        var response = _mocks.DynamicMock<HttpResponseBase>();
        var server = _mocks.DynamicMock<HttpServerUtilityBase>();
        var cache = HttpRuntime.Cache;

        SetupResult.For(httpContext.Request).Return(request);
        SetupResult.For(httpContext.Response).Return(response);
        SetupResult.For(httpContext.Session).Return(testControllerBuilder.Session);
        SetupResult.For(httpContext.Server).Return(server);
        SetupResult.For(httpContext.Cache).Return(cache);

        SetupResult.For(request.QueryString).Return(testControllerBuilder.QueryString);
        SetupResult.For(request.Form).Return(testControllerBuilder.Form);
        SetupResult.For(request.AcceptTypes).Do((Func<string[]>)(() => testControllerBuilder.AcceptTypes));
        SetupResult.For(request.Files).Return((HttpFileCollectionBase)testControllerBuilder.Files);

        Func<NameValueCollection> paramsFunc = () => new NameValueCollection { testControllerBuilder.QueryString, testControllerBuilder.Form };
        SetupResult.For(request.Params).Do(paramsFunc);

        SetupResult.For(request.AppRelativeCurrentExecutionFilePath).Do(
            (Func<string>)(() => testControllerBuilder.AppRelativeCurrentExecutionFilePath));
        SetupResult.For(request.ApplicationPath).Do((Func<string>)(() => testControllerBuilder.ApplicationPath));
        SetupResult.For(request.PathInfo).Do((Func<string>)(() => testControllerBuilder.PathInfo));
        SetupResult.For(request.RawUrl).Do((Func<string>)(() => testControllerBuilder.RawUrl));
        SetupResult.For(response.Status).PropertyBehavior();
        SetupResult.For(httpContext.User).PropertyBehavior();

        _mocks.Replay(httpContext);
        _mocks.Replay(request);
        _mocks.Replay(response);

        testControllerBuilder.HttpContext = httpContext;
    }
}

Things get a little trickier for the Moq version.  Since TestHelper can’t reference Moq directly, it can’t use the API directly.  I decided to use the proxy pattern after reviewing how StructureMap’s AutoMocking Container handles a similar situation.  The builder itself is still very straight forward.  Though the proxy’s methods don’t map one-to-one to the underlying Moq API, they are pretty close:

public class MoqControllerBuilder : IControllerBuilderStrategy
{
    private static Exception _loadException;
    private static MoqProxy _proxy;

    static MoqControllerBuilder()
    {
        try
        {
            _proxy = new MoqProxy();
        }
        catch (Exception ex)
        {
            _loadException = ex;
        }
        
    }

    public void Setup(TestControllerBuilder testControllerBuilder)
    {
        if (_proxy == null)
        {
            throw new InvalidOperationException("Cannot use MoqControllerBuilder because an error occured while loading Moq.",
                                                _loadException);
        }

        var httpContext = _proxy.DynamicMock<HttpContextBase>();

        var request = _proxy.DynamicMock<HttpRequestBase>();
        var response = _proxy.DynamicMock<HttpResponseBase>();
        var server = _proxy.DynamicMock<HttpServerUtilityBase>();
        var cache = HttpRuntime.Cache;

        httpContext.ReturnFor(c => c.Request, request.Object);
        httpContext.ReturnFor(c => c.Response, response.Object);
        httpContext.ReturnFor(c => c.Session, testControllerBuilder.Session);
        httpContext.ReturnFor(c => c.Server, server.Object);
        httpContext.ReturnFor(c => c.Cache, cache);
        httpContext.SetupProperty(c => c.User);

        request.ReturnFor(r => r.QueryString, testControllerBuilder.QueryString);
        request.ReturnFor(r => r.Form, testControllerBuilder.Form);
        request.ReturnFor(r => r.Files, (HttpFileCollectionBase)testControllerBuilder.Files);
        request.CallbackFor(r => r.AcceptTypes, () => testControllerBuilder.AcceptTypes);
        request.CallbackFor(r => r.Params, () => new NameValueCollection { testControllerBuilder.QueryString, testControllerBuilder.Form });
        request.CallbackFor(r => r.AppRelativeCurrentExecutionFilePath, () => testControllerBuilder.AppRelativeCurrentExecutionFilePath);
        request.CallbackFor(r => r.ApplicationPath, () => testControllerBuilder.ApplicationPath);
        request.CallbackFor(r => r.PathInfo, () => testControllerBuilder.PathInfo);
        request.CallbackFor(r => r.RawUrl, () => testControllerBuilder.RawUrl);
        response.SetupProperty(r => r.Status);

        testControllerBuilder.HttpContext = httpContext.Object;
    }
}

The *real* fun happens in the proxy class. First is the MoqProxy class, which handles dynamically loading the Moq API and, using reflection, creating mock objects:

public class MoqProxy
{
    private Type _mockOpenType;

    public MoqProxy()
    {
        Assembly Moq = Assembly.Load("Moq");
        _mockOpenType = Moq.GetType("Moq.Mock`1");

        if (_mockOpenType == null)
        {
            throw new InvalidOperationException("Unable to find Type Moq.Mock<T> in assembly " + Moq.Location);
        }
    }


    public MockProxy<T> DynamicMock<T>()
    {
        return new MockProxy<T>(_mockOpenType.MakeGenericType(typeof(T)));
    }
}

The MockProxy<T> class is the proxy for the underlying Mock<T> type, which is the class used for setting up expectations.  This was a tricky class to implement due to the heavy use of generic parameters, but in the end, I managed to get it working:

public class MockProxy<T>
{
    private readonly Type _mockType;
    private PropertyInfo _objectProperty;
    private object _instance;

    public T Object 
    { 
        get
        {
            return (T)_objectProperty.GetValue(_instance, null);
        }
    }

    public MockProxy(Type mockType)
    {
        _mockType = mockType;
        _instance = Activator.CreateInstance(_mockType);
        _objectProperty = mockType.GetProperty("Object", _mockType);
    }

    private MethodInfo GetSetupMethod<TResult>() {
        var openSetupMethod = _mockType.GetMethods().First(m => m.IsGenericMethod && m.Name == "Setup");
        return openSetupMethod.MakeGenericMethod(typeof(TResult));
    }

    public void ReturnFor<TResult>(Expression<Func<T, TResult>> expression, TResult result)
    {
        var setupMethod = GetSetupMethod<TResult>();
        var setup = setupMethod.Invoke(_instance, new object[] { expression });
        var returnsMethod = setup.GetType().GetMethod("Returns", new [] {typeof(TResult)});
        returnsMethod.Invoke(setup, new object[] { result});
    }

    public void CallbackFor<TResult>(Expression<Func<T, TResult>> expression, Func<TResult> callback)
    {
        var setupMethod = GetSetupMethod<TResult>();
        var setup = setupMethod.Invoke(_instance, new object[] { expression });
        var returnsMethod = setup.GetType().GetMethod("Returns", new[] { typeof(Func<TResult>) });
        returnsMethod.Invoke(setup, new object[] {callback});
    }

    public void SetupProperty<TProperty>(Expression<Func<T, TProperty>> expression)
    {
        var openSetupMethod = _mockType.GetMethods().First(m => m.Name == "SetupProperty" && m.GetParameters().Length == 1);
        var setupMethod = openSetupMethod.MakeGenericMethod(typeof(TProperty));
        setupMethod.Invoke(_instance, new object[] {expression});
    }
}

Reflection is somewhat limited when it comes to working with overloaded generic methods.  I ended up using this approach for finding the desired overload via LINQ. 

With all the pieces in place, the TestControllerBuilder unit tests now pass when using either Rhino Mocks or Moq.  Again, this isn’t my final solution, I’m still waiting on feedback on a few possible approaches to decide what’s going to actually be implemented, but the MoqProxy is probably going to be a key piece of whatever solution I move forward with.