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

2022-06-06 01:30:13 字數 2184 閱讀 4658

(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倍以上!此外,為了讓這些互相耦合的測試通過,你需要新增更多的前置條件,但這樣到頭來實際上證明不了任何事情,處在這樣乙個惡性迴圈中真是一件令人沮喪的事情。

如何激勵同事編寫單元測試?

從管理人員到開發者,每個人都在說單元測試,但是卻很少有人執行。有關單元測試的好處相信大家也能例舉出一二,但很多時候,開發者面對自己的專案 卻無從下手。lurkerbelow在公司裡是唯一執行單元測試的一名開發者,他深知單元測試帶來的好處,也積極提倡單元測試。他甚至與公司的管理層人員 開發者都討論過單...

單元測試 單元測試編寫的原則

公司要求提公升單元測試的質量,其中我作為方案和推動的主導,對開發過程中的單元測試,有了一些思考和總結 單元測試編寫的目的,是面向計算機特性的,基於函式的in out,所以單元測試的好幫手就是斷言,通過不斷的構造輸出並對結果進行斷言,我們就可以針對乙個物件以及它的函式,構建出充足的用例去包裹它,以期望...

JMockit編寫java單元測試

jmockit例項 package test.mock.jmockit import static org.junit.assert.assertequals import mockit.deencapsulation import mockit.expectations import mockit...