开发者

What should be the strategy of unit testing when using IoC?

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 possib开发者_开发技巧ility 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 ?


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);
}


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜