2017年3月5日 星期日

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:
01public interface IFooService
02{
03    string Bar();
04}
05 
06public class FooService: IFooService
07{
08    public string Bar()
09    {
10        return "Bar";
11    }
12}
In order to be able to swap between different DI containers and just for decoupling we define two interfaces in Common project
01// Common service locator interface
02public interface IServiceLocator
03{
04    T Get<T>();
05}
06 
07// Common DI container registration module interface
08public interface IContainerRegistrationModule<T>
09{
10    void Register(T container);
11}
IContainerRegistrationModule will come in handy later and now we can define common service locator for any type of DI container:
01public abstract class DependencyInjectionServiceLocator<TContainer> : IServiceLocator
02{
03    // DI container
04    protected TContainer Container { getprivate set; }
05 
06    protected DependencyInjectionServiceLocator(TContainer container)
07    {
08        Container = container;
09    }
10 
11    public virtual T Get<T>()
12    {
13        return Get<T>(Container);
14    }
15 
16    // Get service instance based on container specific logic
17    protected abstract T Get<T>(TContainer container);
18}
And specific service locator for Unity container:
01// Service locator based on Unity DI container
02 public class CustomUnityServiceLocator : DependencyInjectionServiceLocator<IUnityContainer>
03 {
04     public CustomUnityServiceLocator(IUnityContainer container)
05         base(container)
06     { }
07 
08     // Override base method in order to get service instance based on container specific logic
09     protected override T Get<T>(IUnityContainer container)
10     {
11         return this.Container.Resolve<T>();
12     }
13 }
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.
01public class UnityRegistrationModule : IContainerRegistrationModule<IUnityContainer>
02{
03    // Register dependencies in unity container
04    public void Register(IUnityContainer container)
05    {
06        // register service locator
07        container.RegisterType<IServiceLocator, CustomUnityServiceLocator>();
08 
09        // register services
10        container.RegisterType<IFooService, FooService>();
11    }
12}
And the specific configuration module for Unity:
01public class UnityConfig
02   {
03       private static readonly Lazy<IUnityContainer> Container = newLazy<IUnityContainer>(() =>
04       {
05           var container = new UnityContainer();
06           RegisterTypes(container);
07           return container;
08       });
09 
10       public static IUnityContainer GetUnityContainer()
11       {
12           return Container.Value;
13       }
14 
15       public static void RegisterTypes(IUnityContainer container)
16       {
17           var registrationModuleAssemblyName = System.Configuration.ConfigurationManager.AppSettings["UnityRegistrationModule"];
18 
19           var type = Type.GetType(registrationModuleAssemblyName);
20 
21           var module = (IContainerRegistrationModule<IUnityContainer>)Activator.CreateInstance(type);
22 
23           module.Register(container);
24       }
25   }
Now you can initialize the container like this:
1var 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:
1<?xml version="1.0" encoding="utf-8" ?>
2<configuration>
3   <appSettings>
4 
5     <add key="UnityRegistrationModule"value="Dependency.UnityRegistrationModule, Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
6 
7  </appSettings>
8</configuration>
Finally lets move on to the Test project. First of all lets define the base test class:
01[TestClass]
02  public class TestBase
03  {
04      private static IUnityContainer _unityContainer = null;
05      private static IServiceLocator _serviceLocator = null;
06 
07      private static IUnityContainer UnityContainer
08      {
09          get return _unityContainer ?? (_unityContainer = UnityConfig.GetUnityContainer()); }
10      }
11 
12      private static IServiceLocator ServiceLocator
13      {
14          get return _serviceLocator ?? (_serviceLocator = UnityContainer.Resolve<IServiceLocator>()); }
15      }
16 
17      protected TService GetService<TService>()
18      {
19          return ServiceLocator.Get<TService>();
20      }
21  }
Here we initialize unity container, resolve service locator and define GetService method.
And finally lets create some unit tests:
01[TestClass]
02public class UnitTest1 : TestBase
03{
04    [TestMethod]
05    public void TestMethod1()
06    {
07        var service = this.GetService<IFooService>();
08        var result = service.Bar();
09        Assert.IsTrue(result.Length > 0);
10    }
11}
And here it is - FooService successfully resolved using Unity container and our custom service locator.
Download source code here

from : http://gentlelogic.blogspot.tw/2014/12/c-using-microsoft-unity-dependency.html

沒有留言:

張貼留言