Skip to content

Instantly share code, notes, and snippets.

@trailmax
Created January 18, 2016 12:01
Show Gist options
  • Save trailmax/c84c2a9d9cf0769ff14b to your computer and use it in GitHub Desktop.
Save trailmax/c84c2a9d9cf0769ff14b to your computer and use it in GitHub Desktop.
Automocking with MOQ
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