Created
January 18, 2016 12:01
-
-
Save trailmax/c84c2a9d9cf0769ff14b to your computer and use it in GitHub Desktop.
Automocking with MOQ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Management.Instrumentation; | |
using Autofac; | |
using Autofac.Builder; | |
using Autofac.Core; | |
using Autofac.Features.ResolveAnything; | |
using Moq; | |
using MyProject.Domain.Services.Configuration; | |
using MyProject.Infrastructure.Context; | |
using MyProject.Tests.ZeroFriction.Stubs; | |
namespace MyProject.Tests.ZeroFriction | |
{ | |
/// <summary> | |
/// Attempt to create auto-mocking container based on Autofac and Moq. | |
/// Inspired by http://blog.ploeh.dk/2013/03/11/auto-mocking-container/ | |
/// with help of http://stackoverflow.com/questions/2462340/automockcontainer-with-support-for-automocking-classes-with-non-interface-depend | |
/// | |
/// Have a look on this http://nuget.org/packages/Autofac.Extras.Moq/ | |
/// </summary> | |
public class Automocking | |
{ | |
private IContainer Container { get; set; } | |
public Automocking() | |
{ | |
ConfigurationContext.Current = new StubMyProjectConfiguration(); | |
var builder = new ContainerBuilder(); | |
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); | |
// give it a real context. Have this as delegate, because we don't want to set up context if we don't need it. | |
builder.Register(x => new MyProjectDomainContext()) | |
.SingleInstance(); | |
// provide real repositories | |
builder.RegisterAssemblyTypes(assemblies) | |
.Where(t => t.Name.EndsWith("Repository")) | |
.AsImplementedInterfaces(); | |
builder.RegisterSource(new AutoMockingRegistrationSource()); | |
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource()); | |
Container = builder.Build(); | |
} | |
/// <summary> | |
/// Creates an instance of a class under test, injecting all necessary dependencies as mocks. | |
/// </summary> | |
/// <typeparam name="TSut">Requested object type.</typeparam> | |
public TSut Create<TSut>() | |
{ | |
if (typeof(TSut).IsInterface) | |
{ | |
throw new NotSupportedException("You can not use interfaces as SUT. Please use concrete class implementations"); | |
} | |
var builder = new ContainerBuilder(); | |
builder.RegisterType<TSut>().AsImplementedInterfaces().SingleInstance(); | |
builder.Update(Container); | |
return Container.Resolve<TSut>(); | |
} | |
/// <summary> | |
/// Gets or creates a mock for the given type, with | |
/// the default behaviour specified by the factory. | |
/// </summary> | |
public Mock<T> GetMock<T>() where T : class | |
{ | |
var dependency = Container.Resolve<T>(); | |
var mocked = dependency as IMocked<T>; | |
if (mocked == null && dependency != null) | |
{ | |
throw new InstanceNotFoundException( | |
String.Format("{0} can not be mocked. This resolves to a real class. Please use ResolveDependency<T>()", typeof(T))); | |
} | |
return mocked != null ? mocked.Mock : null; | |
} | |
/// <summary> | |
/// Resolves dependency to an instance of a real class | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <returns></returns> | |
public T ResolveDependency<T>() where T : class | |
{ | |
var dependency = Container.Resolve<T>(); | |
var mocked = dependency as IMocked<T>; | |
if (mocked != null) | |
{ | |
throw new InstanceNotFoundException(String.Format("{0} resolves to a mocked object. Please use GetMock<T>() for that", typeof(T))); | |
} | |
return dependency; | |
} | |
} | |
// http://stackoverflow.com/questions/4851775/autofac-how-to-use-custom-methodproperty-to-resolve-some-interface | |
public class AutoMockingRegistrationSource : IRegistrationSource | |
{ | |
private readonly MockRepository mockRepository; | |
public AutoMockingRegistrationSource() | |
{ | |
this.mockRepository = new MockRepository(MockBehavior.Default); | |
this.mockRepository.CallBase = true; | |
this.mockRepository.DefaultValue = DefaultValue.Mock; | |
} | |
public MockRepository MockRepository | |
{ | |
get { return this.mockRepository; } | |
} | |
public IEnumerable<IComponentRegistration> RegistrationsFor( | |
Service service, | |
Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor) | |
{ | |
var swt = service as IServiceWithType; | |
if (swt == null || !swt.ServiceType.IsInterface) | |
{ | |
yield break; | |
} | |
var existingReg = registrationAccessor(service); | |
if (existingReg.Any()) | |
{ | |
yield break; | |
} | |
var reg = RegistrationBuilder.ForDelegate((c, p) => | |
{ | |
var createMethod = typeof(MockRepository).GetMethod("Create", Type.EmptyTypes).MakeGenericMethod(swt.ServiceType); | |
return ((Mock)createMethod.Invoke(this.MockRepository, null)).Object; | |
}).As(swt.ServiceType).SingleInstance().CreateRegistration(); | |
yield return reg; | |
} | |
public bool IsAdapterForIndividualComponents { get { return false; } } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment