2012-06-01 42 views
3

我正在研究一個較舊的3層設計的項目,添加的任何新功能都需要進行單元測試。如何在沒有DI的緊密耦合的業務數據層上啓用單元測試?

問題是業務層/數據層緊密耦合,如下面的示例。 BL只是報道了一個數據層對象......所以這種模擬幾乎是不可能的。我們沒有實現任何依賴注入,所以構造器注入是不可能的。那麼修改結構的最好方法是什麼,以便可以在不使用DI的情況下模擬數據層?

public class BLLayer() 
{ 

    public GetBLObject(string params) 
    { 
    using(DLayer dl = new DLayer()) 
    { 
     DataSet ds = dl.GetData(params); 

     BL logic here.... 

    } 
    } 
} 
+0

你究竟是什麼意思「依賴注入實現,所以構造函數注入是不可能的。」?你的意思是你不能在你的類中使用構造函數,或者你沒有一個DI容器/框架? – steenhulthin

+0

@steenhulthin我們沒有在項目中啓動和運行DI框架。 – NullReference

+0

稍後在代碼中如何使用dl(dl.GetData(params)調用是否僅將數據檢索到dl對象中)。 – steenhulthin

回答

5

你不能排除構造函數注入本身,你只是沒有一個IOC容器設置。沒關係,你不需要一個。你可以做窮人的依賴注入,並保持構造器注入。

用接口包裝DataLayer,然後創建一個工廠,它將根據命令創建IDataLayer對象。將此字段添加到要嘗試注入的對象中,將所有new替換爲對工廠的調用。現在,你可以注入你的假貨進行測試,這樣的:

interface IDataLayer { ... } 
interface IDataLayerFactory 
{ 
    IDataLayer Create(); 
}  

public class BLLayer() 
{ 
    private IDataLayerFactory _factory; 

    // present a default constructor for your average consumer 
    ctor() : this(new RealFactoryImpl()) {} 

    // but also expose an injectable constructor for tests 
    ctor(IDataLayerFactory factory) 
    { 
    _factory = factory; 
    } 

    public GetBLObject(string params) 
    { 
    using(DLayer dl = _factory.Create()) // replace the "new" 
    { 
     //BL logic here....  
    } 
    } 
} 

不要忘記有你想要的真正的代碼使用實際出廠的默認值。

2

如果DLayer僅用於GetBLObject方法,我會在方法調用中注入一個工廠。喜歡的東西:(上@PaulPhillips例如大廈)

public GetBLObject(string params, IDataLayerFactory dataLayerFactory) 
    { 
     using(DLayer dl = dataLayerFactory.Create()) // replace the "new" 
     { 
      //BL logic here....  
     } 
    } 

但是似乎有什麼你真的想在業務層一起工作是一個DataSet。因此,另一種方法是讓GetBLObject將方法調用中的DataSet替換爲string param。爲了使這項工作,你可以創建一個類,從DLayer只處理DataSet。例如:

public class CallingBusinesslayerCode 
{ 
    public void CallingBusinessLayer() 
    { 
     // It doesn't show from your code what is returned 
     // so here I assume that it is void. 
     new BLLayer().GetBLObject(new BreakingDLayerDependency().GetData("param")); 
    } 
} 

public class BreakingDLayerDependency 
{ 
    public DataSet GetData(string param) 
    { 
     using (DLayer dl = new DLayer()) //you can of course still do ctor injection here in stead of the new DLayer() 
     { 
      return dl.GetData(param); 
     } 
    } 
} 

public class BLLayer 
{ 
    public void GetBLObject(DataSet ds) 
    { 
     // Business Logic using ds here. 
    } 
} 

一個警告:懲戒出DataSet(你必須在這一點,保羅·菲利普斯解決兩者)可真麻煩,所以測試這將是可能的,但不一定有很多樂趣。

+0

有趣的是,關於創建假DataSet的繁重性,我沒有考慮到 –

3

依賴注入只是衆所周知的「控制反轉」概念下的衆多模式之一。主要標準是在組件之間提供「接縫」,以便您可以分開。總之,有多種方法來剝皮貓。依賴注入本身有幾個派生:構造器注入(依賴關係通過構造函數傳入),屬性注入(表示爲讀/寫屬性的依賴關係)和方法注入(依賴關係傳入方法)。這些模式假設這個類是「封閉的修改」並暴露它們的依賴關係以便消費者改變。遺留代碼很少以這種方式設計,並且系統範圍的體系結構更改(例如移動到構造函數注入和IoC容器)並不總是直截了當的。

其他模式涉及在測試下將對象的分辨率和/或構造脫離開。像工廠這樣簡單的四人幫模式可以創造奇蹟。服務定位器就像一個全局對象工廠,雖然我不是這種模式的忠實粉絲,但它可以用來分離依賴關係。

在上面列出的示例中,測試模式「要測試的子類」將允許您在沒有系統範圍的重新體系結構的情況下引入接縫。在該模式中,您將諸如「new DLayer()」之類的對象創建調用移至虛擬方法,然後創建該主題的子類。

Micheal Feather的「使用遺留代碼」有一個模式和技術的目錄,您可以使用這些目錄將您的遺留代碼置於允許您轉向DI的狀態。