Guest User

Untitled

a guest
May 23rd, 2018
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.68 KB | None | 0 0
  1. using System;
  2. using Autofac;
  3. using Autofac.Builder;
  4. using Moq;
  5. using System.Reflection;
  6. using Autofac.Component.Activation;
  7. using Autofac.Component;
  8. using Autofac.Component.Scope;
  9.  
  10. namespace yellowbook.testing.common
  11. {
  12. /// <summary>
  13. /// Auto-mocking factory that can create an instance of the
  14. /// class under test and automatically inject mocks for all its dependencies.
  15. /// </summary>
  16. /// <remarks>
  17. /// Note that only interface dependencies will be mocked for now.
  18. /// </remarks>
  19. public class AutoMockContainer : IResolve
  20. {
  21. IContainer container;
  22. MockFactory factory;
  23.  
  24. /// <summary>
  25. /// Initializes the container with the <see cref="MockFactory"/> that
  26. /// will be used to create dependent mocks.
  27. /// </summary>
  28. public AutoMockContainer(MockFactory factory)
  29. {
  30. this.factory = factory;
  31. var builder = new ContainerBuilder();
  32. builder.Register(this).OwnedByContainer();
  33. this.container = builder.Build();
  34.  
  35. this.container.AddRegistrationSource(new MoqRegistrationSource(this.factory));
  36. }
  37.  
  38. /// <summary>
  39. /// Gets or creates a mock for the given type, with
  40. /// the default behavior specified by the factory.
  41. /// </summary>
  42. public Mock<T> GetMock<T>()
  43. where T : class
  44. {
  45. // TODO: support passing a different MockBehavior ?
  46. var obj = (IMocked<T>)this.Create<T>();
  47. return obj.Mock;
  48. }
  49.  
  50. /// <summary>
  51. /// Creates an instance of a class under test,
  52. /// injecting all necessary dependencies as mocks.
  53. /// </summary>
  54. /// <typeparam name="T">Requested object type.</typeparam>
  55. public T Create<T>() where T : class
  56. {
  57. if (!container.IsRegistered<T>())
  58. {
  59. var builder = new ContainerBuilder();
  60.  
  61. builder.Register<T>();
  62. builder.Build(container);
  63. }
  64.  
  65. return container.Resolve<T>();
  66. }
  67.  
  68. /// <summary>
  69. /// Creates an instance of a class under test using
  70. /// the given activator function.
  71. /// </summary>
  72. /// <typeparam name="T">Requested object type.</typeparam>
  73. public T Create<T>(Func<IResolve, T> activator) where T : class
  74. {
  75. if (!container.IsRegistered<T>())
  76. {
  77. var builder = new ContainerBuilder();
  78.  
  79. builder.Register<T>(c => activator(this));
  80. builder.Build(container);
  81. }
  82.  
  83. return container.Resolve<T>();
  84. }
  85.  
  86. /// <summary>
  87. /// Registers and resolves the given service on the container.
  88. /// </summary>
  89. /// <typeparam name="TService">Service</typeparam>
  90. /// <typeparam name="TImplementation">The implementation of the service.</typeparam>
  91. public void Register<TService, TImplementation>()
  92. {
  93. var builder = new ContainerBuilder();
  94.  
  95. builder.Register<TImplementation>().As<TService>().ContainerScoped();
  96. builder.Build(container);
  97.  
  98. // TODO: why would you need back the instance you have just registered?
  99. // Isn't it supposed to be automatically injected from now on?
  100. //return Resolve<TService>();
  101. }
  102.  
  103. /// <summary>
  104. /// Registers the given service instance on the container.
  105. /// </summary>
  106. /// <typeparam name="TService">Service type.</typeparam>
  107. /// <param name="instance">Service instance.</param>
  108. public void Register<TService>(TService instance)
  109. {
  110. var builder = new ContainerBuilder();
  111.  
  112. builder.Register(instance).As<TService>();
  113. builder.Build(container);
  114. }
  115.  
  116. /// <summary>
  117. /// Registers the given service creation delegate on the container.
  118. /// </summary>
  119. /// <typeparam name="TService">Service type.</typeparam>
  120. public void Register<TService>(Func<IResolve, TService> activator)
  121. {
  122. var builder = new ContainerBuilder();
  123.  
  124. builder.Register(c => activator(this)).As<TService>();
  125. builder.Build(container);
  126. }
  127.  
  128. /// <summary>
  129. /// Resolves a required service of the given type.
  130. /// </summary>
  131. public T Resolve<T>()
  132. {
  133. return container.Resolve<T>();
  134. }
  135.  
  136. /// <summary>
  137. /// Resolves unknown interfaces and Mocks using
  138. /// the <see cref="MockFactory"/> from the scope.
  139. /// </summary>
  140. class MoqRegistrationSource : IRegistrationSource
  141. {
  142. private readonly MockFactory factory;
  143. private readonly MethodInfo createMethod;
  144.  
  145. public MoqRegistrationSource(MockFactory factory)
  146. {
  147. this.factory = factory;
  148. this.createMethod = factory.GetType().GetMethod("Create", new Type[] { });
  149. }
  150.  
  151. /// <summary>
  152. /// Retrieve a registration for an unregistered service, to be used
  153. /// by the container.
  154. /// </summary>
  155. /// <param name="service">The service that was requested.</param>
  156. /// <param name="registration">A registration providing the service.</param>
  157. /// <returns>
  158. /// True if the registration could be created.
  159. /// </returns>
  160. public bool TryGetRegistration
  161. (Service service, out IComponentRegistration registration)
  162. {
  163. if (service == null)
  164. throw new ArgumentNullException("service");
  165.  
  166. registration = null;
  167.  
  168. var typedService = service as TypedService;
  169. if ((typedService == null) || (!typedService.ServiceType.IsInterface))
  170. return false;
  171.  
  172. var descriptor = new Descriptor(
  173. new UniqueService(),
  174. new[] { service },
  175. typedService.ServiceType);
  176.  
  177. registration = new Registration(
  178. descriptor,
  179. new DelegateActivator
  180. ((c, p) =>
  181. {
  182. var specificCreateMethod = this.createMethod.MakeGenericMethod(new[] { typedService.ServiceType });
  183. var mock = (Mock)specificCreateMethod.Invoke(factory, null);
  184. return mock.Object;
  185. }),
  186. new ContainerScope(),
  187. InstanceOwnership.Container);
  188.  
  189. return true;
  190. }
  191. }
  192. }
  193.  
  194. /// <summary>
  195. /// Interface implemented by the <see cref="AutoMockContainer"/> so that
  196. /// the <c>Register</c> overloads can receive a creation
  197. /// function for the service, rather than just a type.
  198. /// </summary>
  199. public interface IResolve
  200. {
  201. /// <summary>
  202. /// Resolves a required service of the given type.
  203. /// </summary>
  204. T Resolve<T>();
  205. }
  206. }
Add Comment
Please, Sign In to add comment