我有一個關於設計類以便測試友好的最佳方式的問題。假設我有一個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類來完成這些任務。 –