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.

Extension Method Issues with Ninject

I thought I'd put this up here quickly as, hopefully, it may be of use to others who've come across and struggled with the extension method issue with Ninject. I've got another post on Ninject and Moq mock injection coming up soon.

If you've used Ninject in your .NET 3.5 projects you may have had occasional problems compiling your solution. If the compiler throws the "Missing compiler required member 'System.Runtime.CompilerServices.ExtensionAttribute..ctor'" error, you've encountered an issue with the Ninject.Core.dll v1.0.0.82 which is currently available from ninject.org.

The issue is discussed here but the solution to the problem isn't very clear. Though, if you read very carefully you'll find that you're encouraged to download the source and re-build Ninject yourself after adding a NET_35 pre-processor directive.

As it turns out, Nate Kohari - father of Ninject - has fixed the issue and published the Ninject SVN trunk on the web. So all you need to do is point your SVN client (I use Tortoise) to http://ninject.googlecode.com/svn/trunk/, pull out the code, and build yourself a release version of the DLLs.

Problem solved!

Tuesday, 14 October 2008

Problems with MVC and Continuous Integration

It seems I don't have much time to write these days, but I've finally got another worthwhile piece to share. After sorting out our issues with MVC Preview 5 on VS2008, we promptly ran into trouble when adding our MVC projects to the Continuous Integration process. The MVC project would not build because of missing DLL references. Steve had installed MVC Preview 5 on the build-server, so this was more than a little odd.

However, after digging around for a while Steve found that this wasn't really an issue with missing DLLs on the build server at all. Rather, it was an issue with a couple of hintpaths in the MVC project file. The project file had stuff in it like this:




Do you see what's going on here? The hint-path is relative, and points to \Program Files\ on the C:\ drive! This is an issue for us, because the actual build happens on the E:\ drive of our build server. So... what to do?

We use Subversion as our source repository, and frequently apply svn:externals to our project repos to pull in common third-party DLLs (such as Moq, NUnit, NInject etc). So why not use the same approach for the culprit MVC DLLs? That's exactly what we did and it solved the problem nicely.

We've got a separate repository called BinaryDependencies which holds all our third-party DLLs. Whenever one or more of these DLLs are required we add a svn:external reference to the BinaryDependecies repository to pull in the relevant DLLs to the local project, and then it's simply a matter of replacing the existing references to Microsoft.Web.Mvc.dll (and any other offending reference that's broken) with a local reference. Simple!

Of course, this isn't a lasting solution because you'll have to update the DLLs in the BinaryDependencies repository every time a new version of MVC comes out. BUT, it does get you up and runnig for now - and besides, MVC's soon going to be in Beta and first release... and I assume these particular problems will have been fixed by then!