Thursday, December 25, 2014

C#: Using Microsoft Unity dependency injection in Unit Tests

After working with Ninject and Windsor for a while I finally faced Microsoft Unity dependency injection container. And here is the way to build up an infrastructure for Unity container to use it for example in Unit tests.

Lets take a look at the solution structure:

Service project contains services.

Common project apart from common interfaces contains service locator implementation.

Dependency project contains Unity configuration and registration classes.

Test project contains unit tests for service layer.

For this particular case there will be only one service in Service project:

    public interface IFooService
    {
        string Bar();
    }

    public class FooService: IFooService
    {
        public string Bar()
        {
            return "Bar";
        }
    }

In order to be able to swap between different DI containers and just for decoupling we define two interfaces in Common project

    // Common service locator interface
    public interface IServiceLocator
    {
        T Get<T>();
    }

    // Common DI container registration module interface
    public interface IContainerRegistrationModule<T>
    {
        void Register(T container);
    }

IContainerRegistrationModule will come in handy later and now we can define common service locator for any type of DI container:

    public abstract class DependencyInjectionServiceLocator<TContainer> : IServiceLocator
    {
        // DI container
        protected TContainer Container { get; private set; }

        protected DependencyInjectionServiceLocator(TContainer container)
        {
            Container = container;
        }

        public virtual T Get<T>()
        {
            return Get<T>(Container);
        }

        // Get service instance based on container specific logic
        protected abstract T Get<T>(TContainer container);
    }

And specific service locator for Unity container:

   // Service locator based on Unity DI container
    public class CustomUnityServiceLocator : DependencyInjectionServiceLocator<IUnityContainer>
    {
        public CustomUnityServiceLocator(IUnityContainer container)
            : base(container)
        { }

        // Override base method in order to get service instance based on container specific logic
        protected override T Get<T>(IUnityContainer container)
        {
            return this.Container.Resolve<T>();
        }
    }

Common project is done, moving on to Dependency project. Here we need to define two classes for later usage. First one is registration module where all dependencies will be registered.

    public class UnityRegistrationModule : IContainerRegistrationModule<IUnityContainer>
    {
        // Register dependencies in unity container
        public void Register(IUnityContainer container)
        {
            // register service locator
            container.RegisterType<IServiceLocator, CustomUnityServiceLocator>();

            // register services
            container.RegisterType<IFooService, FooService>();
        }
    }

And the specific configuration module for Unity:

 public class UnityConfig
    {
        private static readonly Lazy<IUnityContainer> Container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        public static IUnityContainer GetUnityContainer()
        {
            return Container.Value;
        }

        public static void RegisterTypes(IUnityContainer container)
        {
            var registrationModuleAssemblyName = System.Configuration.ConfigurationManager.AppSettings["UnityRegistrationModule"];

            var type = Type.GetType(registrationModuleAssemblyName);

            var module = (IContainerRegistrationModule<IUnityContainer>)Activator.CreateInstance(type);

            module.Register(container);
        }
    }

Now you can initialize the container like this:

var unityContainer = UnityConfig.GetUnityContainer()

Upon calling GetUnityContainer() method new instance of UnityContainer will be initialized, our UnityRegistrationModule will be created and it will register the dependencies.

Notice that UnityRegistrationModule is created via Activator and the assembly and type name added into the App.config configuration file in Test poject:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
   <appSettings>

     <add key="UnityRegistrationModule" value="Dependency.UnityRegistrationModule, Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />

  </appSettings>
</configuration>

Finally lets move on to the Test project. First of all lets define the base test class:

  [TestClass]
    public class TestBase
    {
        private static IUnityContainer _unityContainer = null;
        private static IServiceLocator _serviceLocator = null;

        private static IUnityContainer UnityContainer
        {
            get { return _unityContainer ?? (_unityContainer = UnityConfig.GetUnityContainer()); }
        }

        private static IServiceLocator ServiceLocator
        {
            get { return _serviceLocator ?? (_serviceLocator = UnityContainer.Resolve<IServiceLocator>()); }
        }

        protected TService GetService<TService>()
        {
            return ServiceLocator.Get<TService>();
        }
    }

Here we initialize unity container, resolve service locator and define GetService method.

And finally lets create some unit tests:

    [TestClass]
    public class UnitTest1 : TestBase
    {
        [TestMethod]
        public void TestMethod1()
        {
            var service = this.GetService<IFooService>();
            var result = service.Bar();
            Assert.IsTrue(result.Length > 0);
        }
    }

And here it is - FooService successfully resolved using Unity container and our custom service locator.

Download source code here

No comments :

Post a Comment