DIF*_*DIF 7 c# unit-testing dependency-injection ninject mocking
可能重复:
使用IoC进行单元测试
我认为我确实有一个问题,理解单元测试和/或依赖注入的工作方式.我正在使用NUnit和Rhino Mocks进行单元测试,将Ninject用作依赖性感知框架.一般来说,虽然这两个人都适合完美 - 但不知何故,似乎它变得更加复杂和难以理解.
(我会尝试做一个很好的例子,让它保持干净和轻松.这是关于我,骑自行车).
1.)没有DI /单元测试:
如果不知道DI和单元测试,我的代码看起来就像那样 - 我会很高兴:
public class Person
{
public void Travel()
{
Bike bike = new Bike();
bike.Ride();
}
}
public class Bike
{
public void Ride()
{
Console.WriteLine("Riding a Bike");
}
}
Run Code Online (Sandbox Code Playgroud)
骑我的自行车我只需要: new Person().Travel();
2.)使用DI:
我不希望紧耦合,所以我需要一个接口和一个NinjectModule!我有一些开销,但只要代码易于阅读和理解,那就没问题了.我只是传递修改后的Person类的代码,Bike类没有改变:
public class Person
{
IKernel kernel = new StandardKernel(new TransportationModule());
public void Travel()
{
ITransportation transportation = kernel.Get<ITransportation>();
transportation.Ride();
}
}
Run Code Online (Sandbox Code Playgroud)
我仍然可以骑自行车: new Person().Travel();
3.)考虑单元测试(没有DI):
为了能够检查是否正确调用了Ride-Method,我需要一个模拟.据我所知,有两种注入接口的方法:构造函数注入和Setter注入.我为我的例子选择了Constructor Injection:
public class Person
{
ITransportation transportation;
public person(ITransportation transportation)
{
this.transportation = transportation;
}
public void Travel()
{
transportation.Ride();
}
}
Run Code Online (Sandbox Code Playgroud)
这一次,我想通过自行车: new Person(new Bike()).Travel();
4.)使用DI并准备单元测试3.中
的类考虑单元测试(没有DI)将无需修改即可完成工作,但我需要打电话new Person(kernel.Get<ITransportation>());
.通过这种感觉,我觉得我正在失去DI的好处 - Person类可以在没有任何耦合的情况下调用Travel,并且需要知道什么类型的交通工具.另外,我认为这种形式缺乏示例2的大部分可读性.
这是怎么做的?或者还有其他 - 更优雅的方式实现依赖注入和单元测试(和模拟)的可能性?
(回想起来,似乎这个例子真的很糟糕 - 每个人都应该知道他现在骑的是什么样的交通工具......)
Bro*_*ass 11
通常我会尽量避免使用IoC容器进行单元测试 - 只需使用模拟和存根来传递依赖项.
您的问题从方案2开始:这不是 DI - 这是服务定位器(反)模式.对于真正的依赖注入,您需要传入依赖项,最好是通过构造函数注入.
方案3是好看,这是DI,一般还你如何使在测试你的类隔离 -传递所需要的依赖.我很少发现需要使用完整的DI容器进行单元测试,因为每个被测试的类只有几个依赖项,每个依赖项都可以被存根或模拟来执行测试.
我甚至会争辩说,如果你需要一个IoC容器,你的测试可能不够精细,或者你有太多的依赖.在后一种情况下,一些重构可能是为了从您正在使用的两个或多个依赖关系中形成聚合类(当然,只有在存在任何语义连接时).这最终会将依赖项数量降低到您认为合适的水平.每个人的最大数量是不同的,我个人努力最多只有4个,至少我一方面可以算数,嘲笑不是太多的负担.
反对在单元测试中使用IoC容器的最后一个重要论点是行为测试:如果您没有完全控制依赖关系,如何确保被测试的类按照您希望的方式运行?
可以说,你可以通过使用为某些操作设置标志的类型来删除所有依赖项来实现这一点,但这是一项很大的努力.使用像RhinoMocks或Moq这样的模拟框架来验证使用您指定的参数调用某些方法要容易得多.为此您需要模拟要验证调用的依赖项,IoC容器无法帮助您.