views:

282

answers:

4

After all what I have read about Dependency Injection and IoC I have decided to try to use Windsor Container within our application (it's a 50K LOC multi-layer web app, so I hope it's not an overkill there). I have used a simple static class for wrapping the container and I initialize it when starting the app, which works quite fine for now.

My question is about unit testing. I know that DI is going to make my life much easier there by giving me the possibility of injecting stub / mock implementations of class collaborators to the class under test. I have already written a couple of tests using this technique and it seems to make sense for me. What I am not sure about is whether I should be using IoC (in this case Windsor Castle) also in unit tests (probably somehow configure it to return stubs / mocks for my special cases) or is it better to wire-up all the dependencies manually in the tests. What do you think and what practice has worked for you ?

+7  A: 

You don't need DI container in unit tests because dependencies are provided through mock objects generated with frameworks such as Rhino Mocks or Moq. So for example when you are testing a class that has a dependency on some interface this dependency is usually provided through constructor injection.

public class SomeClassToTest
{
    private readonly ISomeDependentObject _dep;
    public SomeClassToTest(ISomeDependentObject dep)
    {
        _dep = dep;
    }

    public int SomeMethodToTest()
    {
        return _dep.Method1() + _dep.Method2();
    }
}

In your application you will use a DI framework to pass some real implementation of ISomeDependentObject in the constructor which could itself have dependencies on other objects while in a unit test you create a mock object because you only want to test this class in isolation. Example with Rhino Mocks:

[TestMethod]
public void SomeClassToTest_SomeMethodToTest()
{
    // arrange
    var depStub = MockRepository.CreateStub<ISomeDependentObject>();
    var sut = new SomeClassToTest(depStub);
    depStub.Stub(x => x.Method1()).Return(1);
    depStub.Stub(x => x.Method2()).Return(2);

    // act
    var actual = sut.SomeMethodToTest();

    // assert
    Assert.AreEqual(3, actual);
}
Darin Dimitrov
Sounds reasonable. After all, this is exactly what I am doing. I was just not sure whether it's a good practice, especially when there are a lot of dependencies and I have to manually mock them all.
Thomas Wanner
Take a look at the automocking I talked about in my answer Thomas, it really simplifies testing classes with lots of dependencies. :-)
Russell Giddings
A: 

I've just written a very similar style and size app. I wouldn't put any dependency injection in the unit tests because it is not complicated enough to be necessary. You should use a mocking framework to create your mocks (RhinoMocks / Moq).

Also Automocking in Moq or the Auto Mock Container in Rhinomocks will simplify building your mocks further.

Auto mocking allows you to get object of the type you want to test without setting up mocks by hand. All dependencies are mocked automatically (assuming they are interfaces) and injected into the type constructor. If you need to you can set up expected behavior, but you don't have to.

Russell Giddings
Yes, but isn't Auto Mock Container also an IoC container? ;) It's just that it is more relaxed regarding resolving dependencies: it will generate default mock implementation of services without throwing exceptions for unresolved stuff like the "proper" Windsor container does.
Igor Brejc
...and most importantly it only takes two lines to create! The fact that you don't need to register any dependencies means it's loads easier than a regular IoC. Another reasons to using automocking though is to abstract away the call to the object under test's constructor. Therefore, if the signature changes you don't have to change lots of tests, making your test classes less brittle. :-)
Russell Giddings
+1  A: 

I'm working on an ASP.NET MVC project with about 400 unit tests. I am using Ninject for dependency injection and MBUnit for testing.

Ninject is not really necessary for unit testing, but it reduces the amount of code I have to type. I only have to specify once (per project) how my interfaces should be instantiated as opposed to doing this every time I initialize the class being tested.

In order to save time on writing new tests, I have created test fixture base classes with as much generic setup code as possible. The setup procedures in those classes intialize fake repositories, create some test data and a fake identity for the test user. Unit tests only initialize data that is too specific to go into generic setup procedures.

I am also mocking objects (as opposed to faking) in some tests, but I found that faking data repositories results in less work and more accurate tests.

For example, it would be more difficult to check if the method under test I properly commits all updates to the repository after making them when using a repository mock than when I am using a repository fake.

It was quite a bit of work to set up at the beginning, but really helped me reduce save a lot of time in the long run.

Adrian Grigore
A: 

As Darin has already pointed out, you don't need to use DI if you have mocks. (However, DI has a few other benefits as well, including, first of all, lessening dependencies in your code, which makes your code much easier to maintain and extend in the long run.)

I personally prefer wiring up everything in my unit tests, thus relying as little as possible on external frameworks, config files etc.

Péter Török