2014-01-17 17 views
4

我有一個外部庫用來交換消息。 在這個庫中,我有一個名爲Channel的對象。有沒有任何理由更喜歡嘲諷一個界面而不是使用可重寫成員的類?

這是反編譯後的結果的dll:

public class Channel 
{ 
    public State CurrentState { get { /*Only for code compiling, the value depend on the TCP Connection state.*/return State.ERROR; } } 
    public bool Send(string message) 
    { 
     //Some stuff with TCP connection. 
     return true; 
    } 

    public enum State 
    { 
     DISCONNECTED, 
     CONNECTED, 
     ERROR 
    } 
} 

現在在我的代碼,我用這個Channel一類用於發送郵件,類看起來是這樣的:

public class ClientConnection 
{ 
    private Channel MyChannel; 

    public ClientConnection(Channel channel) 
    { 
     MyChannel = channel; 
    } 

    public bool Send(string message) 
    { 
     bool result = false; 
     if(MyChannel.CurrentState == Channel.State.CONNECTED) 
     { 
      result = MyChannel.Send(message); 
     } 
     return result; 
    } 
} 

所以我目標是測試它,驗證send方法是否被調用,並檢查參數是否與我的輸入相匹配。 這裏的問題是沒有接口,方法也不是虛擬的,所以嘲笑是不可能的。

我做了什麼 我創建了重寫的屬性和方法的包裝是這樣的:

public class ChannelWrapper 
{ 
    private readonly Channel channel; 
    public ChannelWrapper(Channel channel) 
    { 
     this.channel = channel; 
    } 
    public virtual Channel.State CurrentState { get { return channel.CurrentState; } } 
    public virtual bool Send(string message) 
    { 
     return channel.Send(message); 
    } 
} 

並在構造函數和財產ClientConnection類型Channel改爲ChannelWrapper

問題 我跌倒,我應該已經創建了使用界面,而不是重寫的成員都ChannelChannelWrapper,和模擬相匹配的額外接口。 同時我真的沒有看到增加一個新接口的意義。

有什麼理由更喜歡嘲笑一個接口而不是帶有可重寫成員的類嗎? (我也主要考慮表現方面)。

+0

順便說一句,我會改變你的發送方法返回void,如果調用channel.Send失敗,拋出一個異常,如果連接不打開。返回布爾值的問題是,您的API的消費者可能會忘記檢查返回值 – Andy

回答

3

你通常想要模擬一個接口而不是一個具體類型的主要原因是,在具體類型的情況下,你的模擬將有實際實現的零碎,可能導致不可預知/不需要的行爲。

例如,通道上的發送方法當前有「//與TCP連接的某些東西」。在裏面。如果Channel類實例化一些Web連接並將它們存儲爲字段會怎樣?這意味着您的模擬對象現在包含實際的Web連接,即使它們可能永遠不會被使用。這可能會更嚴重,如果我們正在談論數據庫連接等。

這可能是你的具體例子不是這種情況,但你應該更多地考慮這次你已經'走開了'而不是規則。這些擔憂意味着它通常會更簡潔地模擬一個界面;你知道你的模擬對象不包含任何你沒有在你的測試中放置的東西。

我也看到這個非常類似的問題:Mocking classes that aren't interfaces

+0

在我的情況下,我有我的包裝和唯一的領域是通道女巫嘲笑時保持空。仍然在一般情況下,請記住+1。 – Thomas

相關問題