2010-01-21 22 views
1

如果我編寫測試代碼來測試我的代碼,測試代碼可能有錯誤,所以需要測試,以及代碼更改時我的測試代碼可能需要更改。無限重複。如何解決TDD中的無限迴歸問題?

這個問題是如何解決的(在實踐上和理論上)?

回答

5

測試測試代碼,代碼測試測試。

當你編寫一個測試,然後編寫足夠的代碼來運行它,測試失敗。然後你編寫代碼使其通過。如果不這樣做 - 如果它在之前通過,則編寫代碼,或者如果它失敗後,出現問題。如果在編寫代碼之前通過測試,那麼顯然測試有問題 - 修復它,直到您遇到紅色並且得到您預期的失敗。如果測試是紅色的並且在編寫代碼後不會變綠,那麼有兩件事情是錯誤的:測試或代碼。找出它,修復它,然後繼續前進。

+1

1以類似的靜脈,斯圖哈洛韋繪製一個平行於雙會計分類賬。 – 2010-01-21 23:47:31

+0

有趣。當代碼改變時,測試也會改變,對嗎?所以這增加了一倍的工作量,但沒有無限的倒退,對嗎? – user128807 2010-01-22 00:36:43

+0

@Michael你有鏈接到Stu Halloway雙重賬簿的東西嗎? – user128807 2010-01-22 00:38:26

0

寫出真正好的測試代碼。完整記錄下來,在寫作時仔細考慮,並且在方法上要有條不紊。此外,如果您儘可能縮短個別測試時間,則可以增加代碼覆蓋率,同時儘可能減少創建錯誤(並且可見)的機會。

+0

@Stefan。如果這工作,那麼你可以將這個想法應用到原始代碼。如果原始代碼可能有缺陷並需要測試,那麼測試代碼肯定會有錯誤。 – user128807 2010-01-21 23:21:32

2

實際上,通過確保測試在通過之前失敗。 TDD不會奇蹟般地消除代碼中存在錯誤的所有能力,它有望減少錯誤數量,但作爲設計技術它更重要。

它真正提高錯誤計數的地方是在重構時。當我重構並破壞了一個由測試建立的舊行爲時,這些測試已經多次拯救了我的培根。

當通過之前測試失敗,你可以放心,你實際上是實現代碼的行爲的方式,使測試通過,使得測試一個有效的。如果您更改了打破測試的代碼,那麼您需要考慮哪一個是正確的,並相應地進行調整。

當我讀了你的問題,我看到一個潛在的期望,TDD將阻止所有的錯誤。它不會。但它會阻止一些。更重要的是,它可以防止重構時出現的錯誤,讓您隨着時間的推移改進設計,而不用擔心退步。

但TDD真正閃耀的地方在於駕駛設計。它可以確保設計正確地考慮依賴關係,它是模塊化的,並且它可以做你期望的事情(而不是做正確的事情 - 這必須是集成或驗收測試的一部分)。

編輯:(在響應評論)我明白你的問題,並試圖回答這個問題。由於我沒有那麼成功,我會再試一次。

如果測試是第一次看到失敗再通,基本概念,它具有被處理,它無法測試任何錯誤(代碼驗證試驗和測試用於測試的代碼)。這顯然取決於生產代碼的通過,所以它測試了一些東西。更重要的是,它不能真正做到。還有更多層面的測試(整合,接受,也許是一般性質量保證),可以解決更深層次的問題。

但我的首要的一點是要挑戰我的理解是這個問題的前提是:怎樣才能TDD提供100%無bug代碼,如果測試本身可能有錯誤。我對這個前提的回答是它不能。它做了其他事情(驅動器設計)。我希望澄清事情。

+0

@義海。我認爲你錯過了這個問題的關鍵。我的觀點是,測試代碼本身可能存在缺陷,因此需要進行測試。因此,存在無限迴歸。 – user128807 2010-01-21 23:20:53

0

單元測試並不意味着100%的防範bug。這只是一種提高代碼質量的技術。從未實踐過TDD的人會認爲,如果增加了一個旨在通過測試的DOH,代碼的整體可靠性不會提高!

解決單元測試的測試問題。這正是您爲什麼首先使測試失敗的原因 - 這是爲了提高測試的質量。這裏再也沒有絕對,但這種做法確實有幫助。像他們說的那樣,測試測試代碼,代碼測試測試。這總比沒有測試好。

只要回去測試並修理它們,當它們破裂時,那麼,就是意味着發生。如果測試結果良好(即粒度細小)並測試一個非常狹窄的用例,他們會提醒您實際代碼將會中斷。

單元測試作爲一種迴歸工具是無價的。宏觀迴歸(代碼編寫後的幾天,幾周,幾年)和微觀迴歸(編寫代碼時)。順便說一下,我完全發明了這些術語。如果他們是Martin Fowler或Bob叔叔所使用的真正術語,那麼這就意味着我和他們一樣精彩:)只是在開玩笑。

如此長時間的迴歸已經被很好地理解了,你在編寫代碼幾個月後就改變了代碼,並且測試會提醒你什麼是壞的。另一方面,微觀迴歸是編寫代碼並慢慢添加功能的時候。如果您沒有測試,那麼您可能會從代碼將要使用的位置開始執行測試,只需修改該代碼即可完成各種場景。後面的代碼會破壞較早的使用案例的風險很高。

使用TDD,您所實現功能的所有用例(測試)都會保留。這意味着你幾乎可以保證,你以後添加的任何內容都不會破​​壞更強大的代碼。

0

儘可能簡單地編寫測試。

然後,您將有一個良性循環,您的代碼變得儘可能簡單以測試測試。

大概的理論就是這樣。

0

這聽起來像你正在考慮編寫單元測試證明是正確的。這是2件獨立的事情。測試代碼提供了一組已知的輸入並驗證了輸出 - 它們應該非常簡單。設置輸入,執行,驗證輸出。測試只檢查是否爲您在測試中實施的場景生成了預期輸出。如果你編寫的測試過於複雜以至於他們自己需要測試,那麼你需要大大簡化你的測試。你不應該爲你的測試代碼編寫測試代碼。

1

這個想法是,單元測試沒有複雜的邏輯......每個基本上都應該包含一個動作和一個關於動作結果或行爲的斷言或斷言。沒有太多的循環或分支邏輯......沒有什麼可能會有任何錯誤不是很明顯,你不會錯過它。所以,正如其他人所說的那樣,你只是不要爲測試編寫測試。

1

我最近在工作中與某人討論過這個問題。提出這個問題的人有一個公平的觀點,但最終,單元測試是一種實用且經過驗證的技術。 TDD增加了進一步的「測試優先」方面,進一步降低了測試不正確的可能性,因爲在編寫任何產品代碼之前它應該會失敗。雖然在我看來,測試是錯誤的,但這個問題更多的是哲學上的爭論,而不是實際的障礙。

,你需要測試代碼來測試測試的參數僅持有任何重量我,當有問題的代碼,形成一個可重複使用的框架或實用類的測試,其他單元測試夾具將使用。

示例: 在NUnit 2.5之前,我們有可重用的數據驅動測試類。它被許多其他測試所使用並依賴於它,而且它相當複雜。肯定很複雜,有bug。所以我們單元測試了測試類。 ..然後,當NUnit 2.5出來時,我們將所有測試交換使用並丟棄了我們自己的實現。

在另一方面,寫得很好的測試代碼很簡單,不包含特殊的邏輯/分支,並有助於提高圍繞生產代碼腳手架。在可能的情況下,我們應該始終在其他經過充分測試的框架中利用這些功能,而不是在我們的測試課中進行任何邏輯。如果常規的單元測試代碼變得足夠複雜以致於有人認爲它可能需要測試,我會認爲這種方法可能有缺陷。