Wednesday, 29 October 2008

Ninject providers and Moq mock injection.

A few months back I stumbled upon Ninject while reading a post on Jonas Follesø's blog. Since then I've been busy architecting a very modular e-commerce solution for a client, and just recently have I started "tying the application together" using Ninject. Ninject makes for very simple dependency injection, indeed. The Ninject approach is so straight forward, in fact, that Ninject isn't just a good framework for Inversion of Control (IoC) - it's an excellent tool for teaching the principles of IoC as well.

I'm not going to go into any detail on how to use Ninject here, though - there are lots of guides and tutorials in the Dojo.

What I will talk about here, however, is a nice little solution for injecting mocked objects using a Ninject binding provider. My solution uses a Service Locator similar to the one Jonas sets out in his article on Silverlight and Ninject, but the focus here is on the binding providers and how to use them in a unit testing scenario. Nonetheless, a quick look at how the Service Locator is used will not go astray.


public class ServiceLocator
{
public IKernel Kernel { get; private set; }

public static ServiceLocator Instance { get; private set; }

public T Get<T>() { return Instance.Kernel.Get<T>(); }

public ServiceLocator(params IModule[] modules)
{
Kernel = new StandardKernel(modules);
Instance = this;
}
}


As you can see, the ServiceLocator class is a singleton. You load it up once for your application, and classes can happily use it to get access to instances of types defined by an interface, such as


ICategoryService svc = ServiceLocator.Instance.Get<ICategoryService>();


I'm building MVC web applications where the controller classes resolve their dependencies in this way, and in order to test these controllers I have to provide the ServiceLocator with bindings to mocks. But I'm probably getting ahead of myself just a little.

Right... I realise I actually have to provide at least a little information on how Ninject works so that you, dear reader, have at least some context. In order to facilitate dependency injection via Ninject, you create a kernel and load this with one or more instances of IModule which contain your bindings. Creation of the kernel might look something like


StandardKernel kernel = new StandardKernel(new MyBindingModule());


where MyBindingModule is a class that contains the bindings I require. Once again, for the sake of brevity I will not explain the intricate detail of how all this works, but for the sake of continuity this is how MyBindingModule might look


public class MyBindingModule : StandardModule
{
public override void Load()
{
Bind<ICategoryService>().To<CategoryService>();
}
}


By creating a kernel and passing in MyBindingModule to it, the kernel will know that whenever you request an instance of ICategoryService it should create a new instance of the concrete class CategoryService and return that back to you.

Now, that's really great and really powerful stuff. You can set up loads of different bindings, even conditional bindings, and the kernel will happily resolve these for you and return you the right instance type whenever you need it. The only issue with this setup is that when it comes to unit testing, where you need to replace some of your standard bindings with mocks, this approach doesn't work.

Why not? Because the kernel, by default, will resolve a binding and return a new instance of the resolved type. If you're going to use mocks, this is no good because you need to have a handle on the actual mock instance so that you can set expectations and verify behaviours etc etc.

Thankfully Ninject's got a nice little feature which allows you to bind a type to a provider. The provider is a class (which you create) that's responsible for creating the object the kernel should return. Typically you'd use a provider when creation of an object is a complex task (e.g. it involves reading configuration files etc). We're not going to create a very complicated object, but we'll use a provider class so that we can ensure that the Ninject kernel resolves its bindings to specific mock instances that we've already created - rather than creating new instances that we have no access to.

Before we go any further, let's just have a look at a simple test that injects a mock into another class. In this test we're going to create a mock for ICategoryService, set an expectation on that mock, then inject the mock into a CategoryController class (by means of its constructor), ask CategoryController to do something for us, and lastly verify that the CategoryController used the mock in the way we expected. Moq's my mocking framework of choice, but you could use any other framework if you like (Rhino Mocks, NMock, EasyMock, TypeMock etc).


[Test]
public void TestAddingCategoryReturnsTrueFromService()
{
Category category = new Category(){ Id = 100};

Mock<ICategoryService> serviceMock = new Mock<ICategoryService>();
serviceMock.Expect(x => x.Add(category)).Returns(true);

CategoryController controller = new CategoryController(serviceMock.Object);
controller.AddNewCategory(category);

serviceMock.VerifyAll();
}


If you are at all familiar with mocking you'll the above test (created with NUnit) should present no mystery (other than it's a bit pointless, perhaps).

We're going to change the scenario a bit, because we've no control over the creation of CategoryController instances, so we can't inject dependencies via the constructor. Instead we'll let the CategoryController's default constructor make use of the ServiceLocator to resolve its dependencies:


public class CategoryController
{
private ICategoryService CategorySvc { get; set; }

public CategoryController()
{
CategorySvc = ServiceLocator.Instance.Get<ICategoryService>();
}
}


Now we can no longer inject the mock directly into our the CategoryController. Instead we have to rely on Ninject to resolve the dependency for us. So now we'll load up the ServiceLocator with an IModule that has a binding to a provider that we can prime with our mock. Hang on tight while we we have a look at our provider:


public class NInjectMockProvider<T> : SimpleProvider<T> where T : class
{
public static Mock<T> Mock { get; set; }

protected override T CreateInstance(IContext context)
{
if (Mock == null){ Mock = new Mock<T>(); }
return Mock.Object;
}
}


It's straight forward, really. Our NInjectMockProvider<T> extends SimpleProvider<T>. The CreateInstance(IContext context) method creates an instance of Mock<T> and assigns this to the static property Mock, unless this is not null, and then returns the mocked object. Armed with this very simple provider and a new binding our test takes on a new shape alltogether. I've included the new test and binding below.


[Test]
public void TestAddingCategoryReturnsTrueFromService()
{
//set up the ServiceLocator
ServiceLocator locator = new ServiceLocator(new MyBindingModule());

Category category = new Category() { Id = 100 };
Mock<ICategoryService> serviceMock = new Mock<ICategoryService>();
serviceMock.Expect(x => x.Add(category)).Returns(true);

NInjectMockProvider<ICategoryService>.Mock = serviceMock;

//this is where the magic happens. The mock's been assigned to the provider, so
//the controller will be automagically injected with the mock instance we
//created above.
CategoryController controller = new CategoryController();

controller.AddNewCategory(category);

serviceMock.VerifyAll();
}

public class MyBindingModule : StandardModule
{
public override void Load()
{
Bind<ICategoryService>().ToProvider(new NInjectMockProvider<ICategoryService>());
}
}


This example is specific to a scenario where we use the Service Locator pattern, but you can use the same approach and the same mock provider class in other situations as well where you'd like Ninject to resolve bindings to existing mock instances.

I've found that the use of NinjectMockProvider<T> makes it easy to inject mocks and easy to read and understand the tests as well. Hopefully this can be of use to some of you out there.

4 comments:

carlos martinez said...

hey oyvind. yeah, ninject is a very simple and nice way of doing DI. fast, fluent and no xml! hope things are going well for you. speak soon, carlos

Anonymous said...

I guess "automagically" is the proper description here! Thank you for the explanation!

dave welling said...

Nice work. This saved me a lot of time.

Bacchusmann said...

Just what I was looking for. And explained very well too.