Creating a generic test base class that will mock dependencies

A base test class using Castle Windsor and the ILazyComponentLoader so I don't have to manually setup my mocks. Uses NSubstitute and NUnit too.
August 28 2013

Technologies used:

  • NSubstitute
  • NUnit
  • Castle Windsor
  • C#

When unit testing I may have a service under test (SUT) that has many dependencies I’ll need to provide mocks/stubs for.  It’s not difficult to setup the SUT by manually creating the mocks, but it’s easier if I don’t have to.  Another reason to avoid manually creating my SUT is if I add dependencies to the SUT I don’t need to add new mocks. Also, if my SUT has parameter dependencies I may forget to inject these if I create the service manually.  Again not a big problem, and I’ll be writing new tests anyway, but still, it’s something I don’t need to manage.

Let’s say I had a class like the following

public class DoStuffService : IDoStuffService
{
    private readonly IRepository1 _repo1;
    private readonly IRepository2 _repo2;
    private readonly IRepository3 _repo3;
    private readonly IAmAnotherSerivce _service;
    private readonly IBus _bus;

    public DoStuffService(IRepository1 repo1, 
                    IRepository2 repo2,
                    IRepository3 repo3,
                    IAmAnotherService service,
                    IBus bus)
    {
        _repo1 = repol;
        _repo2 = repo2;
        _repo3 = repo3;
        _service = service;
        _bus = bus;    
    }

    public bool DoSomething(string myString)
    {
var ent = _repo1.GetById(4); return ent.Name == myString; } }

To test this I would create a fixture

[TestFixture]
public class DoStuffServiceFixture
{
    private DoStuffService _service;
    private IRepository1 _repo1;
    private IRepository2 _repo2;
    private IRepository3 _repo3;
    private IAmAnotherService _anotherService;
    private IBus _bus;

    [SetUp]
    public void SetUp()
    {
        _repo1 = Substitute.For<IRepository1>();
        _repo2 = Substitute.For<IRepository2>();
        _repo3 = Substitute.For<IRepository3>();
        _anotherService = Substitute.For<IAmAService>();
        _bus = Substitute.For<IBus>();

        _service = new DoStuffService(_repo1, _repo2, _repo3, _anotherService, _bus);
    }

   [Test]
    public void Test_my_method() 
    {
        Dep().GetById(4).Returns(new SomeEntity() { Name = "a string" });

        var result = Service.DoSomething("a string");

        Assert.IsTrue(result);
    }
}

When I use the code outside the test my Windsor IoC container, takes care of the dependencies for me.  If it did the same in my tests, I wouldn’t have to worry about the dependencies my service needs, be they injected via constructor or parameter.   I'm using the same method to create my service in my test as I would in production.  (I have tests to test that the container can correctly resolve all required dependencies).

Windsor has an interface, ILazyComponentLoader which adds the component when it’s about to be resolved.   The loader is called by the container when a component is first request for whatever service.  Using this, I created a loader to returned mock components, created by NSubstitute.

public class LazyNSubstituteMocker : ILazyComponentLoader
{
    public IRegistration Load(string key, Type service, IDictionary arguments)
    {
        return Component.For(service).Instance(Substitute.For(new[] {service}, null));
    }
}

I also created a generic base class to handle all this for me, called WindsorTestBase.  It basically creates a WindsorContainer and adds the LazyNSubtituteMocker and the SUT to the container.

/// <summary>
/// Base class to provide unit testing for services by creating 
/// NSubstitute mocks for dependencies of TService.
/// </summary>
/// <typeparam name="TService">The service under test</typeparam>
public abstract class WindsorTestBase<TService> where TService : class
{
    private IWindsorContainer container;

    protected TService Service;

    [SetUp]
    public void SetUp()
    {
        container =
            new WindsorContainer().Register(
                Component.For<ILazyComponentLoader>().ImplementedBy<LazyNSubstituteMocker>(),
                Component.For<TService>());

        DoRegistrations();

        // build sut and inject mocks for all dependancies
        Service = container.Resolve<TService>();

        DoSetUp();
    }

    protected virtual void DoRegistrations() { }

    protected virtual void DoSetUp() { }

    [TearDown]
    public void TearDown()
    {
        DoTearDown();

        container.Dispose();
    }

    protected virtual void DoTearDown() { }    

    protected TDependency Dep<TDependency>()
    {
        return container.Resolve<TDependency>();
    }

    protected TMock Mock<TMock>() where TMock : class
    {
        return Substitute.For<TMock>();
    }

    protected void Register<TMock>(TMock instance) where TMock : class
    {
        container.Register(Component.For<TMock>().Instance(instance));
    }
}

I can add custom registrations as needed.  To access a mocked dependancy I call the Dep method, with the interface for the service I want, eg Dep<IRepository1>().  I can also create Mocks by called Mock<IAnInterface>() or register another service in the container by calling Register<IANewService>(new NewService()). 

Using this base class my test fixture is simplified to

[TestFixture]
public class DoStuffServiceFixture : WindsorTestBase<DoStuffService>
{
    [Test]
    public void Test_my_method() 
    {
        Dep<IRepository1>().GetById(4).Returns(new SomeEntity() { Name = "a string" });

        var result = Service.DoSomething("a string");

        Assert.IsTrue(result);
    }
}

Post a comment

comments powered by Disqus