Jeff Jeff -4 years ago 129
C# Question

Register Generic Interfaces with UnityAutoMoqContainer

We use UnityAutoMoq for mocking most of our interfaces in our unit tests, but I've recently run into a situation where we want to use a test framework to more completely simulate the actual behavior (call it an integration test if that helps you accept what I'm doing).

I expected UnityAutoMoq to let me register concrete mappings instead of allowing the UnityAutoMoqContainer to defer to mocking the interface. This holds true to everything I've tried except for generic interfaces. In case you're visual like me, here's a snippet of what I'm trying:

public static void Register(IUnityContainer container)
{
...
container.RegisterType(typeof(IService<>), typeof(TestFrameworkService<>),
new HierarchicalLifetimeManager(), new InjectionFactory(Create));
...
}

private static object Create(IUnityContainer container, Type type, string name)
{
var T = type.GetGenericArguments().Single();
return new TestFrameworkService<T>();// For simplicity, pretend this works
}


As you can see from above, I'm registering the generic interface to a generic concrete, then depending upon the injection factory to resolve it using the incoming type (the actual implementation was omitted for simplicity). This works with a normal UnityContainer, returning the expected concrete. The UnityAutoMoqContainer returns a mock instead, bypassing the injection factory completely.

Has anyone tried anything like what I'm trying to accomplish? Any ideas?

Answer Source

I found that the problem lies in the underlying BuilderStrategy. Here's a snippet from UnityAutoMoqBuilderStrategy.

public override void PreBuildUp(IBuilderContext context)
{
    var type = context.OriginalBuildKey.Type;

    if (autoMoqContainer.Registrations.Any(r => r.RegisteredType == type))
            return;

    if (type.IsInterface || type.IsAbstract)
    {
        context.Existing = GetOrCreateMock(type);
        context.BuildComplete = true;
    }
}

Bottom line is that the builder strategy sees that the interface isn't registered and intercepts its creation. This is because generic type definitions aren't equal to the generic types, themselves.

I looked into AutoMoq, which was far more recently updated, but it suffers from the same interception limitation that prevents the injection factory from firing.

For reference, here are the automocking libraries that I researched:

If someone has a recommendation, then please let me know, otherwise I'll consider this the answer.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download