2011-10-07 14 views
4

TDD的一個常見做法是,您只需要很小的步驟。但是,有一件事情是我看到一些人做的事情,他們只是硬編碼值/選項,然後重構以使其正常工作。例如...測試驅動開發的初始實現

describe Calculator 
    it should multiply 
    assert Calculator.multiply(4, 2) == 8 

那你就儘可能少的,使其通過:

class Calculator 
    def self.multiply(a, b) 
    return 8 

它呢!

爲什麼人們這樣做?是否要確保他們實際上在正確的課程中實施該方法?因爲如果你忘記了某些東西,它就好像是一種可靠的方式來引入錯誤並給出錯誤的信心。這是一個好習慣嗎?

+0

我希望另一個測試用例能夠抓住硬編碼的返回,如果一個人忘記重構,所以這可能很少見,但我確實看到了你的觀點。即Multiply_WithOneNegativeParameter_ShouldReturnNegativeResult –

回答

5

這種做法被稱爲「假它」,直到你做到了。「換句話說,把虛假的實現放進去,直到放入真正的實現變得更簡單。你問爲什麼我們這樣做。

我這樣做的原因很多。一個是簡單地確保我的測試正在運行。這可能是錯誤的配置,所以當我打我的魔法「運行測試」鍵,我實際上沒有運行測試,我想我正在運行。如果我按下按鈕並且它是紅色的,然後放入假實現並且它是綠色的,我知道我真的在運行我的測試。

這種做法的另一個原因是保持快速的紅/綠/重構節奏。這是驅動TDD的心跳,重要的是它有一個快速的週期。重要的是你可以感受到進步,重要的是你知道你在哪裏。一些問題(顯然不是這個問題)不能一蹴而就地解決,但我們必須在心跳上向前邁進。假裝它,直到你做到這一點,以確保及時進展。另見flow

+1

我也看到它叫'sliming'。過去幾天我一直在使用它,現在它完全有意義。特別是當您編寫單元和集成測試併爲每個測試使用不同的數據/輸入時,您可以確信您不會在代碼中留下「粘液」。 –

4

有一個思想流派,它可以在訓練程序員使用TDD時很有用,也就是說你不應該有任何不屬於單元測試的源代碼行。通過首先對通過測試的算法進行編碼,然後驗證您的核心邏輯是否正常工作。然後,將它重構爲生產代碼可以使用的東西,編寫集成測試來定義交互以及包含此邏輯的對象結構。

另外,宗教TDD的堅持會告訴你,應該沒有邏輯編碼要求,通過單元測試中的斷言進行驗證,並沒有具體說明。例如:在這個時候,系統中乘法的唯一測試就是斷言答案必須是8.所以,在這個時候,答案總是8,因爲要求告訴你沒有什麼不同。

這看起來非常嚴格,而且在這樣的簡單情況下,無意義;爲了在一般情況下驗證正確的功能,當你作爲一個聰明的人「知道」乘法應該如何工作並且可以很容易地建立一個生成並測試一個乘法表的測試時,你將需要無限數量的單元測試達到一定的限度,這會讓你確信它可以在所有必要的情況下工作。然而,在涉及更多算法的更復雜場景中,這對於YAGNI的好處是一個有用的研究。如果需求規定您需要能夠將記錄A保存到數據庫,並且省略了保存記錄B的功能,那麼您必須得出結論「您不需要」保存記錄B的能力,直到滿足要求進來說明了這一點。如果您在知道需要之前實現了保存記錄B的能力,那麼如果事實證明您從不需要那麼就會浪費時間和精力將其融入到系統中;你有沒有商業目的的代碼,無論如何仍然可以「破壞」你的系統,因此需要維護。

即使在更簡單的情況下,如果您編寫的代碼超出了您「知道」太輕或特定的要求,最終編碼可能會超過您的需要。假設您正在爲字符串代碼實施某種解析器。要求聲明字符串代碼「AA」= 1,「AB」= 2,這就是要求的限制。但是,您知道該系統中的完整代碼庫包含20個其他代碼,因此您需要包含解析完整庫的邏輯和測試。你回到客戶身邊,期待你付出時間和材料,客戶說:「我們沒有要求這樣做,我們只使用了我們在測試中指定的兩個代碼,所以我們沒有付錢給你加班」。他們完全正確;你在技術上試圖通過收取他們沒有要求和不需要的代碼來騙取他們。