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

你。 提交于 2019-12-03 10:19:33

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!