2011-05-23 54 views
3

我有一個「配方」方法,我試圖用TDD編寫。它基本上召喚出不同的方法,有時使得基於這些方法的結果決定:單元測試理念

public void HandleNewData(Data data) 
    { 
    var existingDataStore = dataProvider.Find(data.ID); 
    if (data == null) 
     return; 

    UpdateDataStore(existingDataStore, data, CurrentDateTime); 

    NotifyReceivedData(data); 

    if (!dataValidator.Validate(data)) 
     return; 

    //... more operations similar to above 
    } 

我的本能反應是,我確認HandleNewData調用上面傳遞的預期參數見過的方法來啓動編寫測試用例並且在方法調用失敗的情況下返回。 但是這種感覺對我來說就像是一次巨大的投資,用來編寫這樣一個測試,幾乎沒有實際的好處。

那麼寫這樣一個測試的真正好處是什麼?還是真的不值得這麼麻煩?

它似乎只是代碼本身的一個超規範,並且只要代碼需要調用另一個方法或決定不再調用當前方法之一,就會導致維護問題。

回答

9

TDD並不意味着爲已經存在的代碼編寫單元測試(儘管有時在改進遺留代碼時可能有必要)。

你可能聽說過「紅色,綠色,重構」這個詞。這是我們在進行TDD時採取的方法。以下是這三個法律測試驅動開發的,它採取遠一點......

  1. ,直到你寫一個失敗的 單元測試你可能不寫產品代碼 。
  2. 您不可以編寫更多的單元測試,而不足以失敗,並且 不編譯失敗。
  3. 您不能寫出更多的產品代碼,而不足以通過當前失敗測試的 。

採用這種方法的好處是,您的單元測試覆蓋率非常接近100%,並且您知道您的代碼完全按照指定的方式工作。

它會減少維護問題,因爲只要有人對您的代碼進行更改並運行測試,他們就會知道它們是否破壞了任何東西。

在這種情況下,我會在添加任何HandleNewData()之前,爲從HandleNewData()調用的方法遞增地添加單元測試。

向遺留代碼添加單元測試非常困難,但是可行且非常值得。如果你還沒有,我真的推薦閱讀Working Effectively with Legacy CodeMichael Feathers。在爲25年的代碼庫添加單元測試時,我發現它非常寶貴。

+1

我應該澄清,我正在做的是重構一些舊的遺留代碼。我的願望是讓它看起來像上面這個簡單的例子,我試圖用TDD來實現上面的實現 – dmg 2011-05-23 22:46:51

+1

我認爲Johnsyweb的觀點是測試驅動設計首先不會達到上述實現,你有很好的理由難以測試,這是一個警告信號,表明這是一個糟糕的設計。 你當然可以在測試中包裝這個實現,但是如果你的測試沒有綁定到當前的實現上,你也可能想要考慮你的測試會是什麼樣子。如果你要開始一個高層次並深入研究行爲,這個方法將實現你將要寫什麼測試,什麼組件,你能在這裏使用這個結構嗎? – Jonah 2011-05-24 00:10:20

3

您遇到的問題非常普遍。你有一些令人討厭的未經測試的遺留代碼太多了,並且與太多的合作者密切相關。爲此寫一篇測試確實很痛苦。

問題是,你不幸揹負着這個代碼債務,並在某些時候,你將不得不支付。

因此,要開始支付一部分債務,如果您需要更改此代碼,我會盡可能地模擬出測試方法的單個傳遞,以便您可以獲得測試shell適合您添加新功能的地方。如果可能的話,我會把你的新功能調用給另一個協作者,這是你可以放置(和測試驅動器!)你的新代碼的地方。

通過這種方式,您可以確信舊代碼會調用您的新代碼,並且新代碼已通過TDD正確構建。

您當然還有原始遺留代碼的代碼債務,但您可以將其作爲單獨問題來處理。

1

由於您已經澄清它是「Legacy Code(TM)」,因此我將簡單介紹該方法的設計。名字本身是模糊的,這反映在方法的內容中。我會看看改進設計 - 它似乎做了很多。

但要做到這一點,我必須確保我不會以「變得更好」爲藉口而變得更糟。我如何證明這一點?測試!

所以我首先將「副」測試放在頂層對象功能的「塊」上。 所以我把在驗證「HandleNewData」的行爲,今天我所知的測試(這可能包括一些代碼開挖)

  • 查找數據存儲的ID
  • 更新用新的數據和數據存儲修改時間戳
  • 通知感興趣的聽衆
  • 驗證數據(它應該是第2步,從它的外觀) 等。

一旦我通過一些自動「副」測試確定了現有行爲,我現在可以自信地進行更改/改進。也可能是這樣的,一旦設計被重構,HandleNewData的包含類型就不再需要了。在這種情況下,您可以放棄這些測試 - 然而,這些測試在現有改進之間的價值不容忽視。