使用IoC时,unit testing的策略应该是什么?

毕竟我读过有关dependency injection和IoC的内容我已经决定尝试在我们的应用程序中使用Windsor Container(它是一个50K LOC多层Web应用程序,所以我希望它不是一个矫枉过正)。 我已经使用了一个简单的静态类来包装容器,并在启动应用程序时对其进行初始化,这对于现在来说非常好。

我的问题是关于unit testing。 我知道通过让我可以将类协作者的存根/模拟实现注入到被测试的类中,DI将使我的生活变得更加轻松。 我已经使用这种技术编写了几个测试,这似乎对我有意义。 我不确定的是我是否应该在unit testing中使用IoC(在本例中为Windsor Castle)(可能以某种方式将其配置为针对我的特殊情况返回存根/模拟)或者是否更好地连接所有依赖项在测试中手动。 你怎么想,什么做法对你有用?

在unit testing中不需要DI容器,因为依赖关系是通过使用Rhino Mocks或Moq等框架生成的模拟对象提供的。 因此,例如,当您测试一个依赖于某个接口的类时,通常通过构造函数注入提供此依赖项。

public class SomeClassToTest { private readonly ISomeDependentObject _dep; public SomeClassToTest(ISomeDependentObject dep) { _dep = dep; } public int SomeMethodToTest() { return _dep.Method1() + _dep.Method2(); } } 

在您的应用程序中,您将使用DI框架在构造函数中传递ISomeDependentObject一些实际实现,该构造函数本身可能依赖于其他对象,而在unit testing中您创建模拟对象,因为您只想隔离地测试此类。 Rhino Mocks示例:

 [TestMethod] public void SomeClassToTest_SomeMethodToTest() { // arrange var depStub = MockRepository.CreateStub(); 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); } 

我正在开发一个带有大约400个unit testing的ASP.NET MVC项目。 我使用Ninject进行dependency injection,使用MBUnit进行测试。

Ninject对于unit testing来说并不是必需的,但它减少了我必须键入的代码量。 我只需要指定一次(每个项目)我的接口应该如何实例化,而不是每次初始化被测试的类时都这样做。

为了节省编写新测试的时间,我创建了尽可能多的通用设置代码的测试夹具基类。 这些类中的设置过程初始化假存储库,为测试用户创建一些测试数据和虚假标识。 unit testing仅初始化太具体的数据,无法进入通用设置过程。

我在一些测试中也嘲笑对象(而不是伪造),但我发现伪造数据存储库会导致更少的工作和更准确的测试。

例如,在使用存储库模拟时,在使用存储库假时,检查测试中的方法是否正确地将所有更新提交到存储库将更加困难。

在开始时进行设置是相当多的工作,但从长远来看,确实帮助我减少了大量的时间。

我刚刚写了一个非常相似的风格和大小的应用程序。 我不会在unit testing中添加任何dependency injection,因为它不够复杂到必要。 你应该使用一个模拟框架来创建你的模拟(RhinoMocks / Moq)。

Moq中的自动 锁定或Rhinomocks中的Auto Mock容器将进一步简化构建模拟的过程 。

自动模拟允许您获取要测试的类型的对象,而无需手动设置模拟。 所有依赖项都会自动模拟(假设它们是接口)并注入到类型构造函数中。 如果您需要,您可以设置预期的行为,但您不必这样做。

正如达林已经指出的那样,如果你有嘲笑,你不需要使用DI。 (但是,DI还有一些其他好处,首先包括减少代码中的依赖性,这使得代码更容易维护和扩展,从长远来看。)

我个人更喜欢在unit testing中连接所有内容,因此尽可能少地依赖外部框架,配置文件等。