Microsoft Unity Auto Mocking Container?

How to build Microsoft Unity Auto Mocking container in less then 20 minutes of work…

I have written before in detail about Auto Mocking Containers so I’ll skip here details on what is it etc and jump to the main point of this post: implementation of auto mocking container for Microsoft Unity.

Faced with PIA caused by constant explicit mocking of constructor dependencies (some of them not even used in my tests), I’ve tried to Google my way out by searching for Unity AMC on Codeplex, Google code etc. To my surprise that didn’t went well with best match being Roy Osherove Unity AMC container blog post which is just a nice fluent interface allowing explicit mock creation and injection on easier way. In other words, nothing automatic happening there at least not in a sense I needed it for my tests.

I started looking for the Object builder documentation and found some for version one scattered on couple of sites. The only thing I get from that documentation was that ObjectBuilder is one complex thing and “patching it” was far away from my end design goal: quick solution.

So, once I realized that I can not solve this on ninja way I tried “brute force” approach and in 20 minutes I had working Unity AMC.

The idea is simple:

  • create a class specializing the UnityContainer – “AutoMockingUnityContainer”
  • override UnityContainer “Get” methods
  • wrap in try catch block every “Resolve” call
  • if ResolutionFailedException would occur using reflection find greediest constructor (with the most parameters)
  • if no constructor info available, return a mock
  • try to resolve those parameters by using AMC resolve method
  • recourse until you won’t have complete set of arguments needed (real or mocked instances) for constructing the originally requested instance

Code explaining the above mentioned concepts is even simpler so let cut the chase and  save you from pain caused by reading more text written with “my English” ..

“Show me the code”

Imagine we would have a console application which is giving the answer on the meaning of the life

using System;
using Microsoft.Practices.Unity;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            var user = container.Resolve<User>();
            Console.WriteLine(user.WhatIsTheMeaningOfTheLife());
            Console.ReadKey();
        }
    }
}

(Code creates UnityContainer instance and the uses it to retrieve instance of user class which WhatIsTheMeaningOfTheLife method is then shown in console output.)

User class is implemented like this:

namespace ConsoleApplication1
{
    public class User
    {
        private readonly ICompanyManager companyManager;

        public User(ICompanyManager companyManager)
        {
            this.companyManager = companyManager;
        }

        public int WhatIsTheMeaningOfTheLife()
        {
            return 42;
        }
    }
}

(User class constructor accepts ICompanyManager parameter which BTW is totally not used in the method used in console application.)

Although totally irrelevant for this blog post, here’s ICompanyManger class code (just not to have any secrets :)):

namespace ConsoleApplication1
{
    public interface ICompanyManager
    {
        void NotImportantMethod();
    }
}

If I would run this code as it is I would be rewarded by the nice Unity ResolutionFailedException

Resolution of the dependency failed, type = “ConsoleApplication1.User”, name = “”. Exception message is: The current build operation (build key Build Key[ConsoleApplication1.User, null]) failed: The parameter companyManager could not be resolved when attempting to call constructor ConsoleApplication1.User(ConsoleApplication1.ICompanyManager companyManager). (Strategy type BuildPlanStrategy, index 3)

Reason is pretty obvious: Unity container didn’t have any mapping defined for ICompanyManager which is required in order for user class to be required.

AutoMockingUnityContainer

Is just a class looking like this

using System.Diagnostics;
using Microsoft.Practices.Unity;

namespace UnityAMC
{
    public class AutoMockingUnityContainer  : UnityContainer
    {
        private readonly MockingHelper mockingHelper;

        public AutoMockingUnityContainer()
        {
             mockingHelper = new MockingHelper(this);
        }

        public override object Resolve(System.Type t, string name)
        {
            try
            {
                return base.Resolve(t, name);
            }
            catch (ResolutionFailedException)
            {
                Debug.WriteLine(string.Format("Conflict resolution of type:{0}", t));
                return mockingHelper.ConstructInstance(t);
            }

        }
    }
}

As you can see no magic there and it does exactly what everyone would expect:

  • Inherit the UnityContainer
  • Override the Resolve method
  • Adds to that override Try Catch block which in case of ResolutionFailedException exception calls the mockingHelper ConstructInstance method
  • Mocking helper instance is stored in a field and constructed with pointer to current unity container in AMCContainer constructor

MockingHelper class

Is just 90 line long class looking like this:

using System;
using System.Diagnostics;
using System.Reflection;
using Microsoft.Practices.Unity;
using Rhino.Mocks;

namespace UnityAMC
{
    public class MockingHelper
    {
        private readonly IUnityContainer unityContainer;
        readonly MockRepository mockRepository = new MockRepository();
        private const string DebugCategory = "UnityAMC.MockingHelper";

        public MockingHelper(IUnityContainer unityContainer)
        {
            this.unityContainer = unityContainer;
        }

        #region Helper methods
        /// 
        /// Construct the instance.
        /// 
        /// The type which is to be constructed.
        /// An instance of service type.
        public object ConstructInstance(Type serviceType)
        {
            ConstructorInfo constructorInfo;
            try
            {
                constructorInfo = GetGreediestConstructor(serviceType.GetConstructors());
            }
            catch (Exception)
            {
                try
                {
                    Debug.WriteLine(string.Format("Mock created - {0}", serviceType), DebugCategory);

                    // returning mock of service not added to container
                    return this.mockRepository.DynamicMock(serviceType, new object[0]);
                }
                catch (Exception ex2)
                {
                    return new AutoMockingContainerContainerResolutionException(string.Format("Auto mocking failed for type:{0}", serviceType), ex2);
                }
            }

            var constructorParameters = constructorInfo.GetParameters();
            var arguments = new object[constructorParameters.Length];

            var counter = 0;
            foreach (var parameterInfo in constructorParameters)
            {
                arguments[counter++] = this.unityContainer.Resolve(parameterInfo.ParameterType, string.Empty);
            }

            return constructorInfo.Invoke(arguments);
        }

        /// 
        /// Gets the greediest constructor.
        /// 
        /// The constructor infos.
        /// Greediest constructor.
        private static ConstructorInfo GetGreediestConstructor(ConstructorInfo[] constructorInfos)
        {
            if (constructorInfos.Length == 0)
            {
                throw new InvalidOperationException("No available constructors.");
            }

            if (constructorInfos.Length == 1)
            {
                return constructorInfos[0];
            }

            var result = constructorInfos[0];
            for (int i = 1; i < constructorInfos.Length; i++)
            {
                if (constructorInfos[i].GetParameters().Length > result.GetParameters().Length)
                {
                    result = constructorInfos[i];
                }
            }

            return result;
        }
        #endregion
    }
}

GetGreediestConstructor method purpose is to get from a given collection of type constructor info’s the one which has the most arguments.

ConstructInstanceMethod does next things:

  • For a given type tries to get greediest constructor
    • If no constructor available on a given type  (ex. in case of interface) it returns dynamic mock.
  • code then iterates through the greediest constructor parameters and tries to resolve each one of them
  • if resolution of any of them fails the procedure goes again just this time ConstructInstanceMethod would go one level deeper in object graph.

And that’s about it…

If I would modify my console app code to use AutoMockingUnityContainer instead of UnityContainer, I would end with code looking like this

using System;
using Microsoft.Practices.Unity;
using UnityAMC;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            IUnityContainer container = new AutoMockingUnityContainer();
            var user = container.Resolve<User>();
            Console.WriteLine(user.WhatIsTheMeaningOfTheLife());
            Console.ReadKey();
        }
    }
}

Which would run just fine…

image

Conclusion

Although I found this way of doing Unity AMC pretty naive and dumb, it works perfectly in my test fixtures for couple of months already with 20 minutes spent on making it. If anyone do this on ninja way, I would be more then happy to start using that but in the meantime … 🙂

My little code example can be downloaded from here

Technorati Ознаке: ,,,
Advertisements

Posted on April 4, 2009, in Uncategorized. Bookmark the permalink. 2 Comments.

  1. Thanks for linking to this from the complex forums. Ill give it a try.

  2. Excelent work, thanks for sharing

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: