可能是重复的问题:
使用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");
}
}
要骑自行车,我只需要: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();
}
}
我只需要这样就可以骑自行车:new Person().Travel();
3.) 考虑单元测试(不使用DI):
为了能够检查 Ride 方法是否被正确调用,我需要一个 Mock。据我所知,通常有两种方式来注入接口:构造函数注入和Setter 注入。在我的示例中,我选择构造函数注入:
public class Person
{
ITransportation transportation;
public person(ITransportation transportation)
{
this.transportation = transportation;
}
public void Travel()
{
transportation.Ride();
}
}
这次,我需要通过自行车:
new Person(new Bike()).Travel();
4.) 通过 DI 和准备单元测试在3. 不考虑 DI 的情况下,这个类可以不进行修改,但是我需要调用
new Person(kernel.Get<ITransportation>());
。这样做感觉失去了 DI 的好处 - Person 类可以在没有任何耦合和不需要知道交通工具是什么类的情况下调用 Travel 方法。此外,我认为这种形式缺乏示例2中的可读性。这就是做法吗?还是有其他更优雅的方法来实现依赖注入和进行单元测试(和模拟)的可能性?
(回头看,似乎这个例子真的很糟糕 - 每个人都应该知道他目前骑的是什么交通工具...)