天天看點

[翻譯] 如何更好地編寫單元測試(上)

原文來自http://blog.stevensanderson.com/2009/08/24/writing-great-unit-tests-best-and-worst-practises/

(Writing Great Unit Tests: Best and Worst Practices  by:Steve Sanderson)

譯文:

優秀的單元測試與糟糕的單元測試之間的差別是什麼?如何寫出完美的單元測試?這些問題并沒有明确的答案。即使對于一個有十多年經驗的優秀開發者來說,已經掌握的技能和形成的習慣并不能保證讓他寫出好的單元測試,因為單元測試與普通的開發實踐有很大差别,而且大多數人在進行單元測試前已對單元測試的目的産生了一些無用甚至是錯誤的假設。

至少在我看來,大多數單元測試是無用的。我沒有責備開發者的意思,畢竟大多數情況下是公司要求做單元測試,然後他們就安裝了NUnit并開始編寫測試方法了,随後一邊看着紅紅綠綠的标記,一邊想着“我正在進行單元測試”。真正的單元測試并不是這樣的。編寫差的單元測試非常容易,但是這樣編寫的單元測試并不能為項目帶來任何價值,相反,在需求變動的時候卻可能造成“天文數量”的關聯修改。那麼,你現在的情況是不是這樣的?

一、單元測試的目的不是尋找BUG

我非常推崇單元測試,但前提是我們需要正确了解單元測試在“測試驅動開發”(Test Driven Development [TDD])中扮演的角色,并排除自己腦海中關于“單元測試有助于排除BUG”的錯誤想法。

經驗告訴我,單元測試并不是發現BUG或是回歸測試的有效方法。按照定義來看,單元測試是要對軟體中的每個最小獨立單元進行的測試。但是當你的軟體在真實場景運作時,所有的獨立單元都必須互相合作,這就導緻軟體整體的複雜度遠遠超過了單元測試用例數目的總和。能夠證明X和Y子產品能夠獨立工作,并不代表它們能與另外的子產品合作無間;而且,使用者回報的問題往往看起來與單個子產品的缺陷毫無關聯;另外,你編寫的測試用例并不能保證覆寫所有的情況,也就不能檢測出所有可能發生的問題(例如,網絡請求可能受到一些預料之外的幹擾)。

是以,如果你的目的是發現BUG,那麼更有效的做法是模拟生産環境并把軟體整個運作一遍,就像正常的人工測試那樣。如果你建構了一系列測試用例并讓它們自動運作來暴露将來可能發生的問題,這又屬于內建測試的範疇了,內建測試與單元測試涉及到不同的技術。下面是一些關于不同測試方法的使用建議:

[翻譯] 如何更好地編寫單元測試(上)

注:關于單元測試,也會有一種例外的情況确實是為了發現BUG。比如在你重構某個子產品的代碼但并不打算改變該子產品的原有行為時,使用單元測試可以保證子產品的行為确實不會被改變。

那麼,既然單元測試不是用來發現BUG,它的作用到底是什麼呢?

關于這個問題的答案,我敢打賭你已經聽說過不下上百次了,但由于我們大多數開發者腦中關于單元測試的錯誤觀念相當頑固,我還是決定在這兒重複一下。就像TDD領域的專家說的:“TDD是一種開發流程,而不是一種測試流程”,我在這兒延伸一下:“TDD是一種互動式地設計健壯的軟體子產品或單元的方法,而且可以通過單元測試來驗證這些子產品或單元的行為是否符合預期”。

二、優秀的單元測試和糟糕的單元測試

TDD有助于讓你傳遞符合預期的代碼單元。優秀的單元測試具有極高的價值,它可以闡述你的設計、可以讓重構變得容易,還可以讓你在擴充代碼之前對每個單元的行為有一個清晰的整體印象。

相反,糟糕的單元測試則是相當有害的,它并不能清楚地闡述任何事情,卻會妨礙你的重構工作,并會時不時得向你抛出錯誤。

來看看在下面的坐标中,你的做法處于哪個位置?

[翻譯] 如何更好地編寫單元測試(上)

如果是按照TDD的流程建立的單元測試,那麼應該與坐标軸最左邊的情況相符。如果代碼單元的行為改變,那麼單元測試必須随之改變,反之亦然。但是這些單元測試與别的代碼是毫不相關的,是以其它代碼的更改不應該導緻單元測試不通過(如果你的測試代碼無法通過,說明你做的并不是真正的單元測試)。這樣測試代碼的維護成本就會很低,這也是TDD能夠作為一種開發技術被應用于各種規模的項目中的原因。

在坐标軸的另一端的是內建測試,內建測試不會關心代碼單元層面的問題,它從使用者的角度出發,考量的是系統整體的運作情況。內建測試的維護成本也是很低的,因為無論你怎樣修改内部代碼,最終展現給使用者的功能是不應該變化的。

如果你處在坐标軸的中間位置,說明你并不清楚自己在作何假設、在嘗試證明什麼。在這種情況,任何一處微小的單元代碼的變動都可能迫使你去修改上百個看起來無關的單元測試用例,你是以會耗費大量的時間,有時甚至會達到你正常修改代碼所需時間的10倍以上!此外,為了讓這些互相耦合的測試通過,你需要添加更多的前置條件,但這樣到頭來實際上證明不了任何事情,處在這樣一個惡性循環中真是一件令人沮喪的事情。

繼續閱讀