How do you Mock IUnityContainer

Mar 16, 2009 at 5:22 PM
I'm trying to Mock the IUnityContainer using Moq 3.0

I'm getting a BadImageFormatException, but not when debugging. From the looks of it I'm not the only one that's ran into this problem.

here

And its a registered issue for Moq

here

I'm just curious if anyone has found a solution... closest I've found is a nice solution that uses RhinoMock by Roy Osherove

here

but I really like Moq! So I don't really want to have to switch to Rhino Mock but I will if I must

Thanks in advance!

Mar 16, 2009 at 6:44 PM
I've played around with this a bit and I think it revolves around the fluent interface pattern used in Unity. I personally am a huge fan, but whenever I use it with Moq it seems to break. My guess is it's an IL generation issue with the return type, but I've never tried to save off a Moq dynamic proxy to check. Our solution so far was to either use a real unity container in testing or create a full mock class for it. Not pretty, but it works, and we as a practice tend to limit the number of points where we inject the actual IoC container.
Mar 16, 2009 at 7:01 PM
@dpiessens [quote] Our solution so far was to either use a real unity container in testing or create a full mock class for it. Not pretty, but it works [/quote]

I've had to do this as well it just really sucks to have to do that. I just don't understand... its just an interface, you'd think it'd be simply to Mock it
Mar 16, 2009 at 8:43 PM
Ah but it not just an interface... most interfaces don't return themselves as the return type of a method. Not that this shouldn't be supported but it's a design pattern that most likely wasn't tested for. I'd guess that there's a boxing issue on the return type of the dynamic method that's causing the issue. Dynamic IL is not easy to write (I've done it a few times) and can be even more difficult to debug.
Mar 16, 2009 at 10:02 PM
My understanding is that it's an issue with the underlying Castle DynamicProxy code that's used by both Moq and Rhino. So you won't have any more luck using Rhinomocks, I'm afraid.

I'm really curious why you feel the need to mock IUnityContainer? You're not testing the container, are you? Why? We used hand-written mocks (derive from UnityContainerBase, btw, not IUnityContainer directly. You get the brainless overloads implemented for free that way) inside the Unity unit test suite. It was sufficient for what we needed and wasn't that hard to do.

-Chris


Mar 16, 2009 at 11:03 PM
Thanks for replying Chris...

The reason I want to Mock the unity container is so that I can mock its behavior without having to configure it and create a mock implementation... for example.


   14 /// <summary>

   15     /// Summary description for SampleForTavaras

   16     /// </summary>

   17     [TestClass]

   18     public class SampleForTavares

   19     {

   20         private Mock<IUnityContainer> mockUnityContainer;

   21         private Mock<ILogger> mockLogger;

   22         private Mock<IValidate> mockValidator;

   23 

   24         [TestMethod]

   25         public void Can_Mock_Unity()

   26         {

   27             mockUnityContainer = new Mock<IUnityContainer>();

   28             mockLogger = new Mock<ILogger>();

   29             mockValidator = new Mock<IValidate>();

   30 

   31             //set up validator

   32             mockValidator.Setup(mv => mv.Validate(It.IsAny<Address>())).Returns(true);

   33 

   34             //set up container

   35             mockUnityContainer

   36                 .Setup(mc => mc.Resolve<IValidate>("AddressValidator")).Returns(mockValidator.Object);

   37 

   38             var myClass = new MyClass(mockUnityContainer.Object, mockLogger.Object);

   39 

   40             var result = myClass.GetAddress();

   41 

   42             //assert something was returned

   43             Assert.IsNotNull(result);

   44 

   45             //verify expected calls were made

   46             mockUnityContainer.VerifyAll();

   47             mockValidator.VerifyAll();

   48 

   49             //verify logger never called

   50             mockLogger.Verify(

   51                 l => l.Write(It.IsAny<string>(), It.IsAny<CategoryType>(), It.IsAny<PriorityType>()),

   52                 Times.Never());

   53         }

   54 

   55 

   56     }

   57 

   58     public class MyClass

   59     {

   60         private IUnityContainer container;

   61         private ILogger logger;

   62         public MyClass(IUnityContainer container,

   63             ILogger logger)

   64         {

   65             this.container = container;

   66             this.logger = logger;

   67         }

   68 

   69         public Address GetAddress()

   70         {

   71             // Do some stuff... this would call IRepository or something like that

   72             Address address = GetSomeData();

   73 

   74             //Validate it

   75             IValidate validator = container.Resolve<IValidate>("AddressValidator");

   76             if(validator.Validate(address))

   77                 return address;

   78 

   79             // If it fails

   80             logger.Write("Hey it's not valid", CategoryType.Validation, PriorityType.Medium);

   81 

   82             throw new InvalidOperationException("Address invalid");

   83         }

   84 

   85         //used to show quickly, don't flame me :)

   86         private Address GetSomeData()

   87         {

   88             return new Address { Id = 0, Street = "test" };

   89         }

   90     }


Maybe you can suggest a better way or am I just totally complicating things...

Thanks a lot..

Whats really odd is, this code works perfect if you run the test in Debug mode...
Fails if you run it without debug with the following message

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





May 18, 2009 at 11:37 PM

The reason you would want to mock the IUnityContainer is to avoid testing it.  Otherwise, not mocking it includes execution of the actual unity bits alongside the SUT you are trying to isolate.

I ran into this same issue today as well.  According to a few sources I've read, it seems this is actually an issue with the .Net framework itself, and is only being revealed through Castle.DynamicProxy code.  It appears to me to be the same issue reported over 3 years ago (https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=93389).

May 27, 2009 at 6:52 PM

Has anyone found a work-around?  The tests that the Composite Application Guidance Quickstarts have actually instatiate a Unity Container.  I'm not fond of this because it adds more of my own code (prone its own set of errors) in my tests.

May 29, 2009 at 4:28 AM

Why is:

mockUnityContainer.Setup(mc => mc.Resolve<IValidate>("AddressValidator")).Returns(mockValidator.Object);

better than:

realUnityContainer.RegisterInstance<IValidate>(mockValidator.Object);

It's odd that you would want to mock the UnityContainer in the first place. It shouldn't be used directly by your application anyway, the container should just be used to wire up your application at runtime.

May 29, 2009 at 4:43 PM
Edited May 29, 2009 at 4:46 PM

The reason I would need to mock the unity container is because I haven't figured out how to easily configure unity to inject a specific type registered with a key.

 

For example, say you want to set up validation that shares the same interface, but you want to use unity to instantiate it so it is easier to test. With unity you can register several types to the same interface with a key.

ie;

unityContainer.RegisterType<IValidate, PersonValidator>("PersonValidator");

unityContainer.RegisterType<IValidate, OrderValidator>("OrderValidator");

unityContainer.RegisterType<IValidate, ProductValidator>("ProductValidator");

 

You can't easily set up unity to constructor inject IValidate and get a specific validator.

Like this:

 

   76         private readonly IValidate _validate;

   77         public SomeDomainService(IValidate validate)

   78         {

   79             _validate = validate;

   80         }

 

It doesn't know that you actually want,

unityContainer.Resolve<IValidate>("PersonValidator");

The problem lies in that when you try to mock, IUnityContainer you get this exeption:

System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B).

but it doesn't throw when you run it in debug mode... which is really strange.

I agree that it is much better to load the entire object tree rather than using the container directly in your class. I would actually highly advise against doing this. IMO you should never inject IUnityContainer into a class unless you have a very good reason for doing so, such as wiring up you modules on initialization.

If you must mock the behavior of unity or any IoC container for that matter I have found that using IServiceLocator is a much more elegant solution. Here is a quick example please excuse the code it simply demonstrates the ability to mock unity using Microsoft.Practices.ServiceLocation - IServiceLocator

 

    1 #region using

    2 

    3 using System.Collections.Generic;

    4 using System.Linq;

    5 using Microsoft.Practices.ServiceLocation;

    6 using Microsoft.VisualStudio.TestTools.UnitTesting;

    7 using Moq;

    8 

    9 #endregion

   10 

   11 namespace MockUnity

   12 {

   13     /// <summary>

   14     /// Summary description for MockUnityFixture

   15     /// </summary>

   16     [TestClass]

   17     public class MockUnityFixture

   18     {

   19         private Mock<IDataService> _mockDataService;

   20         private Mock<IServiceLocator> _mockServiceLocator;

   21         private Mock<IValidate> _mockValidator;

   22 

   23         [TestInitialize]

   24         public void Setup()

   25         {

   26             _mockValidator = new Mock<IValidate>();

   27             _mockServiceLocator = new Mock<IServiceLocator>();

   28             _mockDataService = new Mock<IDataService>();

   29 

   30             _mockValidator.Setup(mv => mv.Validate("Valid")).Returns(true);

   31 

   32             _mockDataService.Setup(md => md.GetSomeData()).Returns(new[]

   33                                                                        {

   34                                                                            "Valid",

   35                                                                            "Valid",

   36                                                                            "InValid",

   37                                                                            "Valid"

   38                                                                        });

   39             _mockServiceLocator.Setup(msl => msl.GetInstance<IValidate>("SomeInstanceWithAKey")).

   40                 Returns(_mockValidator.Object);

   41         }

   42 

   43         [TestMethod]

   44         public void GetSomeValidDataOnlyReturnsValidData()

   45         {

   46             var someDomainService = new SomeDomainService(_mockServiceLocator.Object,

   47                                                           _mockDataService.Object);

   48 

   49             var results = someDomainService.GetSomeValidData();

   50 

   51             Assert.IsTrue(results.Length == 3);

   52             foreach (var result in results)

   53             {

   54                 Assert.IsTrue(result == "Valid");

   55             }

   56         }

   57     }

   58 

   59     public interface IValidate

   60     {

   61         bool Validate<T>(T entity);

   62     }

   63 

   64     public class SomeDomainService

   65     {

   66         private readonly IDataService _dataService;

   67         private readonly IServiceLocator _serviceLocator;

   68 

   69         private readonly IValidate _validate;

   70 

   71         public SomeDomainService(IServiceLocator serviceLocator,

   72                                  IDataService dataService)

   73         {

   74             _serviceLocator = serviceLocator;

   75             _dataService = dataService;

   76         }

   77 

   78         public SomeDomainService(IValidate validate)

   79         {

   80             _validate = validate;

   81         }

   82 

   83         public string[] GetSomeValidData()

   84         {

   85             var validator = _serviceLocator

   86                 .GetInstance<IValidate>("SomeInstanceWithAKey");

   87 

   88             IList<string> data = new List<string>();

   89 

   90             foreach (var result in _dataService.GetSomeData())

   91             {

   92                 if (validator.Validate(result))

   93                 {

   94                     data.Add(result);

   95                 }

   96             }

   97 

   98             return data.ToArray();

   99         }

  100     }

  101 

  102     public interface IDataService

  103     {

  104         string[] GetSomeData();

  105     }

  106 }

 

May 29, 2009 at 5:12 PM

In my original post, I forgot to name the mock validator, it should have been:

realUnityContainer.RegisterInstance<IValidate>("AddressValidator", mockValidator.Object);

>> You can't easily set up unity to constructor inject IValidate and get a specific validator.

This is what I do:

unityContainer.RegisterType<IValidate, PersonValidator>("PersonValidator");
unityContainer.Configure<InjectedMembers>().ConfigureInjectionFor<SomeDomainService>(
  new InjectionConstructor(new ResolvedParameter<IValidate>("PersonValidator")));

Granted, it's not easy but that's the way I do it with Unity.

>> I have found that using IServiceLocator is a much more elegant solution.

I agree, I have used IServiceLocator for situations where I needed to use a the "service locator" pattern from within my app but wanted to avoid using Unity directly.

May 31, 2009 at 3:37 AM

Why am I mocking the Unity container?  I'm migrating the Composite Application Guidance framework quickstarts module fixture to make use of Rhino.  The test fixture for the module itself checks to see if the module properly registers modules into the container.  Frankly I think this is a major defect and if MS is unable/unwilling to fix the Fx, then Unity should be made to work around the defect in the Fx.  IMHO, or course.

Jun 1, 2009 at 2:35 PM

@bittondb

IServiceLocator is a great work around for mocking the Resolve functionality of Unity.

>> The test fixture for the module itself checks to see if the module properly registers modules into the container.  Frankly I think this is a major defect

If you intent is to test if things are registered properly, I don't think it is a defect at all. Instantiating a new container is probably the best way to go about testing the container.

Jun 4, 2009 at 1:14 AM

I wanted to throw out the idea of using a container extension as another approach to whatever problem you are trying to solve by mocking the container. For example, I had a situation where I wanted to make sure I was getting back the correct named instance so I did something like:

 

I wrote a detailed post on using an extension to accomplish this here:

http://blog.agileatwork.com/testing-unity-container-configuration/

    [Test]
    public void Should_inject_named_instance_of_encryption_provider()
    {
        var service = container.Resolve<MyService>();

        AssertNamedInstanceWasResolved<IEncryptionProvider>("MyEncryptionProvider");
    }
Jun 4, 2009 at 12:12 PM

@bittondb The interface for the Unity container shouldn't have to change to accommodate a bug in the CLR.  If anything, the mocking containers should attempt to create workarounds for this sort of issue until it can be resolved in the BCL.

@rauh_ryan When testing whether a component is registering things properly with the container, this indeed seems the only way to do it.  That said, what you really want to test is that your component is registering the appropriate types, not that the container is working properly.  Additionally, there isn't a clean way to test whether types were actually registered without mocking the interface or without resolving the registered types.  There is no reason you should have to instantiate a type in order to see if it was properly registered.  There are workarounds for this as well.  Overall, passing in real instances of dependencies to the component you are trying to test isn't ideal in any scenario I can think of.

 

Jun 5, 2009 at 7:22 AM

I am well aware of the lack of easily used container introspection in Unity. We'll be adding a bunch of "IsRegistered" type methods in Unity 2.0 to make testing if your components registered the right things a lot easier.

I don't have a whole lot of interest in warping Unity's interface to work around this CLR bug when the actual affected code is the mocking frameworks, not Unity itself. Especially when, as mentioned above, if you're using DI correctly the actual container shouldn't be used anywhere except at the very beginning of your app.

 

Jun 6, 2009 at 1:31 AM
Remember something here, I'm just porting the Quickstarts that MS
wrote. I'm not really interesting in debating whether the test itself
is correct.

On Fri, Jun 5, 2009 at 2:22 AM, [email removed] wrote:
> From: ctavares
>
> I am well aware of the lack of easily used container introspection in Unity.
> We'll be adding a bunch of "IsRegistered" type methods in Unity 2.0 to make
> testing if your components registered the right things a lot easier.
>
> I don't have a whole lot of interest in warping Unity's interface to work
> around this CLR bug when the actual affected code is the mocking frameworks,
> not Unity itself. Especially when, as mentioned above, if you're using DI
> correctly the actual container shouldn't be used anywhere except at the very
> beginning of your app.
>
>
>
> Read the full discussion online.
>
> To add a post to this discussion, reply to this email
> ([email removed])
>
> To start a new discussion for this project, email
> [email removed]
>
> You are receiving this email because you subscribed to this discussion on
> CodePlex. You can unsubscribe on codePlex.com.
>
> Please note: Images and attachments will be removed from emails. Any posts
> to this discussion will also be available online at codeplex.com



--

---
David B. Bitton
Code No Evil, LLC

Code Made Fresh Daily.