我有一个关于设计类以便测试友好的最佳方式的问题。假设我有一个OrderService类,用于放置新订单,检查订单状态等。该类将需要访问客户信息,库存信息,运输信息等。因此,OrderService类将需要使用CustomerService,InventoryService和ShippingService。每个服务还有其自己的后备库。测试友好架构
什么是设计OrderService类可以轻松测试的最佳方式?我见过的两种常用模式是依赖注入和服务定位器。对于依赖注入,我会做这样的事情:
class OrderService
{
private ICustomerService CustomerService { get; set; }
private IInventoryService InventoryService { get; set; }
private IShippingService ShippingService { get; set; }
private IOrderRepository Repository { get; set; }
// Normal constructor
public OrderService()
{
this.CustomerService = new CustomerService();
this.InventoryService = new InventoryService();
this.ShippingService = new ShippingService();
this.Repository = new OrderRepository();
}
// Constructor used for testing
public OrderService(
ICustomerService customerService,
IInventoryService inventoryService,
IShippingService shippingService,
IOrderRepository repository)
{
this.CustomerService = customerService;
this.InventoryService = inventoryService;
this.ShippingService = shippingService;
this.Repository = repository;
}
}
// Within my unit test
[TestMethod]
public void TestSomething()
{
OrderService orderService = new OrderService(
new FakeCustomerService(),
new FakeInventoryService(),
new FakeShippingService(),
new FakeOrderRepository());
}
这个缺点是,每次我创造,我使用的测试中OrderService对象时,它需要大量的代码来调用我的测试中的构造函数。我的服务类也最终为他们使用的每个服务和存储库类提供了一堆属性。随着我扩展我的程序并在各种Service和Repository类之间添加更多依赖关系,我必须返回并为我已经创建的类的构造函数添加越来越多的参数。
对于一个服务定位器模式,我可以做这样的事情:
class OrderService
{
private CustomerService CustomerService { get; set; }
private InventoryService InventoryService { get; set; }
private ShippingService ShippingService { get; set; }
private OrderRepository Repository { get; set; }
// Normal constructor
public OrderService()
{
ServiceLocator serviceLocator = new ServiceLocator();
this.CustomerService = serviceLocator.CreateCustomerService()
this.InventoryService = serviceLocator.CreateInventoryService();
this.ShippingService = serviceLocator.CreateShippingService();
this.Repository = serviceLocator.CreateOrderRepository();
}
// Constructor used for testing
public OrderService(IServiceLocator serviceLocator)
{
this.CustomerService = serviceLocator.CreateCustomerService()
this.InventoryService = serviceLocator.CreateInventoryService();
this.ShippingService = serviceLocator.CreateShippingService();
this.Repository = serviceLocator.CreateOrderRepository();
}
}
// Within a unit test
[TestMethod]
public void TestSomething()
{
OrderService orderService = new OrderService(new TestServiceLocator());
}
我怎么样在更少的代码服务定位器模式的结果调用构造函数的时候,但它也给缺乏灵活性。
什么是建立我的服务类与其他几个服务和存储库的依赖关系,以便他们可以很容易地测试?我所展示的方式之一还是两者都好,还是有更好的方法?
只要在第二个例子中删除“正常的构造函数”,你就很好。但你可能想重新考虑单一责任原则。为什么这个类需要这么多的依赖关系? – CSharpie
研究依赖注入和IOC框架,然后你可以模拟依赖关系,并专注于测试类的核心功能。 –
CSharpie - 它需要所有这些依赖性,因为创建新订单涉及检查客户信用,检查库存,检查运输时间等。让代码在OrderService类中完成所有这些操作会使其变得非常庞大,所以我有其他的Service类来完成这些任务。 –