Aug 7 2009

Mocking IUnityContainer and avoiding BadImageFormatException

Category: .NetRory Primrose @ 08:30

There is an issue with mocking IUnityContainer from RhinoMocks. A BadImageFormatException is thrown when you attempt to create a mock or a stub of IUnityContainer. For example:

using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;

namespace TestProject1
{
    public interface ITestInterface
    {
        void DoSomething();
    }

    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void MockingIUnityContainerFailsTest()
        {
            // This throws a BadImageFormatException
            IUnityContainer container = MockRepository.GenerateStub<IUnityContainer>();
            ITestInterface test = MockRepository.GenerateStub<ITestInterface>();

            container.Stub(x => x.Resolve<ITestInterface>()).Return(test);

            ITestInterface resolvedTest = container.Resolve<ITestInterface>();

            resolvedTest.DoSomething();
        }
    }
}

This test results in the following failure:

Test method TestProject1.UnitTest1.MockingIUnityContainerFailsTest threw exception: System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B).

System.Reflection.Emit.TypeBuilder._TermCreateClass(Int32 handle, Module module)
System.Reflection.Emit.TypeBuilder.CreateTypeNoLock()
System.Reflection.Emit.TypeBuilder.CreateType()
Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
Castle.DynamicProxy.Generators.Emitters.AbstractTypeEmitter.BuildType()
Castle.DynamicProxy.Generators.InterfaceProxyWithTargetGenerator.GenerateCode(Type proxyTargetType, Type[] interfaces, ProxyGenerationOptions options)
Castle.DynamicProxy.DefaultProxyBuilder.CreateInterfaceProxyTypeWithoutTarget(Type theInterface, Type[] interfaces, ProxyGenerationOptions options)
Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyTypeWithoutTarget(Type theInterface, Type[] interfaces, ProxyGenerationOptions options)
Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type theInterface, Type[] interfaces, ProxyGenerationOptions options, IInterceptor[] interceptors)
Castle.DynamicProxy.ProxyGenerator.CreateInterfaceProxyWithoutTarget(Type theInterface, Type[] interfaces, IInterceptor[] interceptors)
Rhino.Mocks.MockRepository.MockInterface(CreateMockState mockStateFactory, Type type, Type[] extras)
Rhino.Mocks.MockRepository.CreateMockObject(Type type, CreateMockState factory, Type[] extras, Object[] argumentsForConstructor)
Rhino.Mocks.MockRepository.Stub(Type type, Object[] argumentsForConstructor)
Rhino.Mocks.MockRepository.GenerateStub(Type type, Object[] argumentsForConstructor)
Rhino.Mocks.MockRepository.GenerateStub[T](Object[] argumentsForConstructor)
TestProject1.UnitTest1.MockingIUnityContainerFailsTest() in C:\Users\rprimrose\Documents\Visual Studio 2008\Projects\TestProject1\TestProject1\UnitTest1.cs: line 19

You can see in the stack trace that this is not actually an issue with RhinoMocks but an issue with Castle. As Moq also uses Castle internally it suffers from the same problem. Many people have raised this as an issue and asked for a solution. There does not seem to be an adequate answer out there other than a solution from Roy Osherove which is a bit heavy handed for what I want.

The answer is actually really simple. Reflector indicates the inheritance hierarchy of IUnityContainer as the following.

You can use either of these types to get the expected outcome and avoiding the BadImageFormatException. This exception seems to be an issue with mocking/stubbing the interface rather than its implemented types.

For example, both of the following tests pass.

[TestMethod]
public void MockingUnityContainerBaseSucceedsTest()
{
    IUnityContainer container = MockRepository.GenerateStub<UnityContainerBase>();
    ITestInterface test = MockRepository.GenerateStub<ITestInterface>();

    container.Stub(x => x.Resolve<ITestInterface>()).Return(test);

    ITestInterface resolvedTest = container.Resolve<ITestInterface>();

    resolvedTest.DoSomething();
}

[TestMethod]
public void MockingUnityContainerSucceedsTest()
{
    IUnityContainer container = MockRepository.GenerateStub<UnityContainer>();
    ITestInterface test = MockRepository.GenerateStub<ITestInterface>();

    container.Stub(x => x.Resolve<ITestInterface>()).Return(test);

    ITestInterface resolvedTest = container.Resolve<ITestInterface>();

    resolvedTest.DoSomething();
}

Easy fix.

Tags: ,

Comments

1.
trackback IvanF says:

Mock Dependency Injection Unity con Rhino Mocks a 64 bit: System.BadImageFormatException

Mock Dependency Injection Unity con Rhino Mocks a 64 bit: System.BadImageFormatException

2.
Lee Oades Lee Oades United Kingdom says:

Nice, thanks!

I've been searching around for a workaround to this .net bug that didn't include a vast amount of refactoring.

Search for:

var mockContainer = new Moq.Mock<IUnityContainer>();

and Replace with:

var mockContainer = new Moq.Mock<UnityContainer>();

... works very nicely, Thanks!

I've a feeling that Mocking the UnityContainer (rather than IUnityContainer) is using the real container and just mocking out the calls to the specified methods (i.e. possible room for different behaviour over just mocking out the interface) - but I'm not too worried about that.

Thanks again!
Lee

3.
Eric Eric United States says:

Any idea why mocking one of the derivatives work, but not the interface itself?

public interface IContainer
{
  void RegisterType<TFrom, TTo>() where TTo : TFrom
}

I can't mock even this interface out.  I tried created a base class from it, and mock out that base class, but still the same problem.  

If I can figure out what is done to UnityContainer that makes it mockable, maybe I can apply that to my base class.

4.
Rory Rory Australia says:

Hi Eric,

Sorry, no idea. I have done some reading up on if there is any published reason, but the only reference I can find is that this issue is apparently fixed (http://www.mail-archive.com/rhinomocks@googlegroups.com/msg02063.html). I am not sure when this will make it into a RhinoMocks or Moq release though.

5.
Rory Rory Australia says:

This issue has been fixed with Unity 2 (released with Enterprise Library 5) and you can now go back to mocking IUnityContainer.

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading