2012-03-02 59 views
6

我是一個用C#編寫的.Net開發人員,我被分配給一個項目,它的管理員希望對它進行徹底的單元測試,主要強調隔離,以便一個邏輯錯誤理想地失敗測試,並且測試之間沒有依賴關係。單元測試添加/獲取方法對

今天我們討論的測試模式,以下問題已arised:

假設我們有一個名爲MyHashTable一個對象,它實現:

void Add(string key, string value); 

string GetValue(string key); 

我們要測試的每個這些方法獨立。當然,主要問題在邏輯上我們無法得到我們從未添加過的東西,並且我們無法驗證沒有得到它而添加的東西。我們已經聽說並瞭解了可能有助於克服這些問題的存根/嘲諷和其他技術,但無法確定哪種解決方案最具可讀性和可維護性。

因此,我要求提供建議/想法如何獨立地測試這些方法,並且如果可以,請包括您的建議的優缺點。謝謝!

+0

請澄清,是MyHashTable你實現自己和要測試的內部,或者只是你使用的「原樣」,想測試的外部接口的類的實例的類型的對象? – 2012-03-02 08:15:04

回答

2

如果你想實現完全獨立和隔離,那麼你就極有可能暴露的MyHashTable一些內部。例如,下面的集合,Add添加元素:

public class MyHashTable<TKey, TValue> 
{ 
    internal Dictionary<TKey, TValue> Storage { get; set; } 
    // ... 
} 

這是不是很漂亮,你可以看到,但就像我說的,這是不可能的,以測試在完全隔離這兩種方法沒有暴露的東西 (就像你注意到的,這是一種方法)。你自然可以提供其他方式來初始化你的課程,例如。與構造函數採取集合,但它只是進一步委託問題 - 你需要驗證構造函數的工作,以及你可能需要Get方法...這將你帶回到原來的問題。

編輯:

請注意,我不建議暴露內部/實施細則遵循的唯一路徑。您可以簡單地將這些方法一起測試(不是在單個測試中,而是在使用其他測試),這可能被證明是更好的解決方案。當然 - 如果你的Add在某些時候失敗了,Get測試也會失敗。但是,再次,你想修復破損Add - 一旦完成了一切都恢復正常。問題自然在於你如何區分它是否被破壞 - 是否是AddGet - 但這正是我在評論中鏈接的正確斷言失敗消息或警戒聲明概念派上用場的原因。

事實是,有時候完全分離和隔離太難以實現,或者只是需要你引入糟糕的設計。這是他們永遠不應該成爲最終目標的原因之一。

+0

所以基本上這些方法必須被視爲一對,並且不能彼此獨立地進行測試。你有沒有在你的測試項目中允許一組測試相互依賴而不是完全隔離?有沒有需要被固定在隔離的概念,如果這意味着要開始添加奇怪的內部或其他東西,只會讓被測少maintanable – Eldar 2012-03-02 08:24:31

+0

@ user1244563代碼:這裏的問題是,有些事情就無法進行測試完全隔離(你的'Add' /'Get'就是最好的例子),除非你公開一些關於它們內部工作的額外信息(在這種情況下 - 他們工作的集合)。我認爲假設他們中的一個在某些時候起作用並且依賴於後者(我認爲你可能有興趣檢查[這些](http://stackoverflow.com/q/9018142/343266)[two ](http://stackoverflow.com/q/9385715/343266)問題)。 – 2012-03-02 08:31:40

+0

揭示內部運作是我強烈不同意的......不是因爲我是封裝怪胎(儘管我不是孤立怪胎),而是因爲有一天我可能想要使用,可以說,MemCache作爲我的內部存儲。所以現在我所有的測試都必須進行重構。我不希望測試依賴內部工作方式,因爲我不希望我的API客戶端對它們進行中繼(測試實際上只是另一個API客戶端)。我只會在代碼需要調用其他代碼(交互測試)時這樣做,因爲我想確保分離問題,確保在需要時使用API​​,而不是其他任何代碼。 – Eldar 2012-03-02 08:51:42

0

爲什麼?單元測試的目的是確保測試方法按預期工作。沒有說你不能使用其他方法來確保測試方法正常工作。

以下測試是由我的罰款(對散列表實施方案)

[Fact] 
public void AddNewItem() 
{ 
    var hashTable = new MyHashTable(); 

    hashTable.Add("hello", "world"); 

    Assert.True(hashTable.Exists("hello")); 
    Assert.Equal("world", hashTable["hello"]); 
} 

[Fact] 
public void AddExistingItem() 
{ 
    var hashTable = new MyHashTable(); 

    hashTable.Add("hello", "world"); 
    hashTable.Add("hello", "realItem"); 

    Assert.Equal("realItem", hashTable["hello"]); 
} 

你當然可以打出來的內部存儲到一個界面,並在構造函數中注入它:

public class MyHashTable 
(
    public MyHashTable(IKeyValueStorage storage) 
    {} 

    // creates a default storage class 
    public MyHashTable() 
    {} 
) 

這允許您嘲笑存儲並因此一次測試一種方法。但這只是將問題進一步推進。你將如何測試存儲實現?

我想說的是,一個HashTable是小型的,孤立單元。使用它的方法來測試它很好。因爲您可以嘲笑它們的依賴關係,所以您不會有域模型的問題。