I have read Mark Seeman's article on auto-mocking and I'm now writing a re-usable windsor container based on that article.
My implementation of Mark's article (basically copied directly)
The main work is done in the AutoMoqResolver
class. This will provide a mock whenever a class has a dependency on an interface:
public class AutoMoqResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public AutoMoqResolver(IKernel kernel)
{
this.kernel = kernel;
}
public bool CanResolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return dependency.TargetType.IsInterface;
}
public object Resolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
var mockType = typeof(Mock<>).MakeGenericType(dependency.TargetType);
return ((Mock)this.kernel.Resolve(mockType)).Object;
}
}
The AutoMoqResolver
is added to the container using the following implementation of the IWindsorInstaller
interface:
public class AutoMockInstaller<T> : IWindsorInstaller
{
public void Install(
IWindsorContainer container,
IConfigurationStore store)
{
container.Kernel.Resolver.AddSubResolver(
new AutoMoqResolver(container.Kernel));
container.Register(Component.For(typeof(Mock<>)));
container.Register(Classes
.FromAssemblyContaining<T>()
.Pick()
.WithServiceSelf()
.LifestyleTransient());
}
}
Then my container simply runs the installer and it is ready to automatically provide mocks for any interface dependencies in unit tests:
public class AutoMockContainer<T> : WindsorContainer
{
public AutoMockContainer()
{
// simply run the auto-mock installer
this.Install(new AutoMockInstaller<T>());
}
}
Super!
I've tested this and my dependencies are happily mocked automatically so I then went to apply it to some real code. This is when I realised that the solution doesn't help me because of the pattern I tend to follow when testing a class. My specific issue is that I want to be able to auto-mock the SUT itself in order to verify that one method on the SUT is called from another.
My code that needs to be tested
I'll explain myself by way of an example. I am developing MVC code and I am supporting unobtrusive AJAX using the following general pattern:
public Class ExampleController : Controller
{
private IService service;
public ExampleController(IService service)
{
this.service = service;
}
public PartialViewResult DoSomethingWithAjax()
{
this.PerformTask();
return this.PartialView();
}
public RedirectToRouteResult DoSomethingWithoutAjax()
{
this.PerformTask();
return this.RedirectToAction("SomeAction");
}
protected virtual void PerformTask()
{
// do something here
}
}
My test pattern
So in order to verify that the PerformTask()
method was called from DoSomethingWithAjax()
or DoSomethingWithoutAjax()
, I define a new TestableExampleController
class like this:
public class TestableExampleController : ExampleController
{
public TestableExampleController(IService service) : base(service)
{
}
public virtual void PerfomTaskPublic()
{
base.PerfomTask();
}
protected override void PerformTask()
{
this.PerformTaskPublic();
}
}
I can then use TestableExampleController
as my SUT so the following test will pass:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a mock TestableExampleController
var controllerMock = new Mock<TestableExampleController>();
controllerMock.CallBase = true;
// use the mock controller as the SUT
var sut = controllerMock.Object;
//// Act
sut.DoSomethingAjax();
//// Assert
controllerMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
My problem
Refactoring this test to use my AutoMockContainer
class like this doesn't work:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a container
var container = new AutoMockContainer<TestableExampleController>();
// resolve a mock SUT using the container
var controllerMock = container.Resolve<Mock<TestableExampleController>>();
controllerMock .CallBase = true;
// use the mock controller as the SUT
var sut = controllerMock.Object;
//// Act
sut.DoSomethingAjax();
//// Assert
controllerMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
The test fails to create an instance of Mock<TestableExampleController>
because it can't find a parameterless constructor.
Can not instantiate proxy of class: MyNamespace.TestableExampleController. Could not find a parameterless constructor. Parameter name: constructorArguments
My proposed solution
Ideally I would like to implement a wrapper class which can be registered with the container to automatically provide a mock for any component:
public class ComponentWrapper<T> where T : class
{
public ComponentWrapper(Mock<T> componentMock)
{
componentMock.CallBase = true;
this.ComponentMock = componentMock;
}
public Mock<T> ComponentMock { get; private set; }
public T Component
{
get { return this.ComponentMock.Object; }
}
}
I would like to be able to write the following test that passes:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a container
var container = new AutoMockContainer<TestableExampleController>();
// resolve a ComponentWrapper using the container
var wrapper = container.Resolve<ComponentWrapper<TestableExampleController>>();
//// Act
// call a method using the component
wrapper.Component.DoSomethingAjax();
//// Assert
// verify a method call using the mock
wrapper.ComponentMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
I can't quite get my head round how to achieve this and I've spent most of the day fiddling with new ISubDependencyResolver implementations but I just can't get this to work.
Hopefully my question is clear and the answer is actually relatively simple?
It turns out that AutoFixture.AutoMoq will do exactly what I want out of the box so thank you to TrueWill for pointing me in the right direction.
The following simple test will pass:
[TestMethod]
public void Run_Calls_DoSomethingProtected()
{
//// Arrange
// AutoMoqCustomization allows AutoFixture to
// be used an an auto-mocking container
var fixture = new Fixture().Customize(new AutoMoqCustomization());
// simply ask the fixture to create a mock
var sutMock = fixture.Create<Mock<TestableDummySystem>>();
//// Act
// exercise the mock object
sutMock.Object.Run();
//// Assert
// this verification passes!
sutMock.Verify(x => x.DoSomethingProtectedPublic());
}