2009-09-18 19 views
11

我一直都是測試驅動開發的實踐者,總的來說我很滿意。我還不知道的一個部分是,你應該始終對單元測試'最小的單位'。爲什麼始終單元測試最小可能的代碼單元是最佳做法?我發現那些測試永遠不會在重構中生存

部分單元測試的想法似乎是讓你有信心重構你不會破壞任何東西。然而,我發現測試非常小的代碼片段的測試幾乎不會在這些重構中倖存下來,代碼總是變化很大,以至於小的單元測試會被丟棄並寫入新的測試。正是這些測試覆蓋了大部分似乎在這裏給予最大價值的功能,因爲更高層次的接口不會經常改變。對於瑣碎的重構,就像移動方法一樣,這些都是通過IDE完成的,而且由於我使用的是靜態類型語言,因此我從未遇到過IDE無法做到的情況重構完美。

其他人有類似或相反的經歷?

回答

10

我發現了同樣的事情 - 但我認爲有一點是很重要的區別是私有代碼單元和公共可訪問的代碼單元之間。我認爲始終對單元測試「在公共API中暴露的最小可用代碼單元」進行單元測試非常重要。

公共API不應在重構期間更改(因爲它會破壞二進制兼容性和版本控制),所以此問題確實存在。

至於私人API,這裏有一個平衡點。您測試的越小,您就越可以依賴您的測試。測試越高級別越高,測試越靈活,並且越有可能在重構中倖存下來。

這就是說,我相信這兩者都很重要。大規模的重構總是需要重新測試 - 這只是測試的一部分。

2

這是一個粒度問題,如金髮姑娘和三隻熊。你想要的東西不是太小,不是太大,但是恰到好處。

如果粒度太小,那麼你可能發現這是浪費時間。如果它太大,那麼它可能會錯過重構/重新配置中應該保持不變的重要限制等。

像任何「最佳實踐」一樣,這些想法通常在理論上發展起來,但需要一些常識和剪裁情況對你有用。

2

在我看來,測試代碼的單位越小,您從測試失敗中獲得的信息就越多。如果您有更高級別的測試涵蓋更大的代碼,那麼失敗會告訴您更少的問題。

+0

那又如何?測試失敗是一個相對罕見的事件 - 我看不到維持微型測試真正付出的時間。 – 2009-09-18 17:12:14

+0

夠公平的。我的意思是,肯定會有收益遞減的跡象。 – 2009-09-18 17:20:27

1

大多數時候我只是單元測試公共類和方法。因爲我認爲,正如你所說,私人成員太動盪不安,容易發生變化。

對私人和內部成員的修改表明您更改了內部算法,而對公共成員的修改則表示語義修改。如果我認爲改變一個私人成員會改變我的班級的語義,那麼,也許這個成員畢竟不應該是私人的。

在你的類的內部算法重構過程中引入的一個bug在語義層面打破了90%的時間測試,而且大多數時候,如果你經常測試和早期測試,bug很快就會被發現。

1

它聽起來並不像你在做真正的Test-Driven Development,它需要一個迭代週期,爲一小段功能編寫測試,創建滿足測試的功能,然後重構以消除任何重複測試/代碼可能已添加。這聽起來像是在事實之後進行測試(「代碼總是變化很大,以至於小的單元測試纔會被扔掉」)。如果一個測試是一個功能規範(就像在TDD中那樣),重構決不會導致測試「不能生存」。

因此,假設您並未真正開展TDD工作,您就需要花費多少測試代碼來編寫代碼,而不是花費多少時間來開發生產代碼。我會說,編寫足夠的測試代碼,讓你知道你的代碼做它應該做的。如果你能用更粗粒度的測試來做到這一點,那麼很好,儘管正如其他人所說的那樣,這使得知道導致失敗的原因更加困難。

測試不僅僅是爲了重構。它知道你什麼時候完成。所以你可以放心地添加新的功能,你不會打破舊的。它是如此之後,你早已離開別人可以進來了解你的代碼,改變它,並確信它的工作原理。

我建議您按照Kent Beck所述的TDD練習。事後編寫測試總比沒有測試好,但我發現它的生產力比TDD低很多。

1

我一直在關注更多的BDD方法,最終我沒有像測試結果那樣測試功能。這樣做時,您仍然在測試功能,但按照預期的結果進行衡量。我發現這樣做會使你的測試更有意義,更脆弱,更適用,而我最終只寫出更少的測試。

相關問題