views:

562

answers:

5

I'm just wondering what the best practice is for rewiring the bindings in a kernel.

I have a class with a kernel and a private class module with the default production bindings.

For tests I want to override these bindings so I can swap in my Test Doubles / Mocks objects.

does

MyClass.Kernel.Load(new InlineModule(m=> m.Bind<IDepend>().To<TestDoubleDepend>()))

override any existing bindings for IDepend?

A: 

I would add a constructor to MyClass that accepts a Module.
This wouldn't be used in production but would be used in test.
In the test code I would pass a Module that defined the test doubles required.

Hamish Smith
+1  A: 

What I tend to do is have a separate test project complete with it's own bindings -- I'm of course assuming that we're talking about unit tests of some sort. The test project uses its own kernel and loads the module in the test project into that kernel. The tests in the project are executed during CI builds and by full builds executed from a build script, though the tests are never deployed into production.

I realize your project/solution setup may not allow this sort of organization, but it seems to be pretty typical from what I've seen.

Peter Meyer
+3  A: 

I try to use the DI kernel directly in my code as little as possible, instead relying on constructor injection (or properties in select cases, such as Attribute classes). Where I must, however, I use an abstraction layer, so that I can set the DI kernel object, making it mockable in unit tests.

For example:

public interface IDependencyResolver : IDisposable
{
    T GetImplementationOf<T>();
}

public static class DependencyResolver
{
    private static IDependencyResolver s_resolver;

    public static T GetImplementationOf<T>()
    {
        return s_resolver.GetImplementationOf<T>();
    }

    public static void RegisterResolver( IDependencyResolver resolver )
    {
        s_resolver = resolver;
    }

    public static void DisposeResolver()
    {
        s_resolver.Dispose();
    }
}

Using a pattern like this, you can set the IDependencyResolver from unit tests by calling RegisterResolver with a mock or fake implementation that returns whatever objects you want without having to wire up full modules. It also has a secondary benefit of abstracting your code from a particular IoC container, should you choose to switch to a different one in the future.

Naturally, you'd also want to add additional methods to IDependencyResolver as your needs dictate, I'm just including the basics here as an example. Yes, this would then require that you write a super simple wrapper around the Ninject kernel which implements IDependencyResolver as well.

The reason you want to do this is that your unit tests should really only be testing one thing and by using your actual IoC container, you're really exercising more than the one class under test, which can lead to false negatives that make your tests brittle and (more importantly) shake developer faith in their accuracy over time. This can lead to test apathy and abandonment since it becomes possible for tests to fail but the software to still work correctly ("don't worry, that one always fails, it's not a big deal").

krohrbaugh
+1 for the resolver pattern, however, REALLY try to use constructor injection in your MyClass that takes IDepend. that way, your unit tests don't even need your IoC container.
dave thieben
+1  A: 

Peter Mayer's approach shuoul be useful for Unit Test, but IMHO, isn't it easier to just inject manually a Mock using a constructor/property injection?

Seems to me that using specific bindings for a test project will be more useful for other kind of test (integration, functional) but even in that case you surely need to change the bindings depending on the test.

My approach is some kind of a mix of kronhrbaugh and Hamish Smith, creatin a "dependency resolver" where you can register and unregister the modules to be used.

Ricky AH
I actually agree with you. In most of my own unit tests, I'm doing "manual" injection -- which sounds too fancy for simply passing a mock to a constructor! I've used DI in unit tests in some isolated, specific cases, but certainly a minority of instances.
Peter Meyer
A: 

For a project I am working on, I created separate modules for each environment (test, development, stage, production, etc.). Those modules define the bindings.

Because dev, stage and production all use many of the same bindings, I created a common module they all derive from. Each one then adds it environment specific bindings.

I also have a KernelFactory, that when handed an environment token will spool up an IKernel with the appropriate modules.

This allows me to switch my environment token which will in turn change all of my bindings automatically.

But if this is for unit testing, I agree with the above comments that a simple constructor allowing manual binding is the way to go as it keeps Ninject out of your tests.

Matthew