原文:WRITE AWESOME UNIT TESTS
作者:molsjeroen導讀:本文作者主要闡述了應該如何做好單元測試,并給出了三點建議:1.單元測試必須跑得足夠快(秒級);2.每個測試用例只針對一個問題;3.避免影響因素,做到 100% 可靠性。
PS: 文章在個人博客上同步更新,敬請關注!
如果你會寫代碼,那么你就會寫單元測試。然而寫好單元測試就是另一個話題了。你以為單元測試代碼是需要你長期維護、重構和開發的產品級代碼?別傻了!
本文旨在提供 3 個十分簡單的規則來幫你玩兒轉單元測試。每個規則之后都會給你提供可輕易實現的實用技巧。
1.要跑的足夠快
寫測試的目的就是為了運行他們。主要有兩個好處:
- 確保程序正常執行
- 程序異常是查找原因
總體而言,測試是程序的安全保障,是避免回歸測試的主要武器。它們使得你可以重構代碼而不會引入已經修復的 bug。
然而,需要注意的是:你需要執行它們以使它們正常工作。
每次執行測試,它都會給你一個代碼狀況的反饋。反饋所用的時間越短,你找到問題的速度就越快,問題也就被修復的越快。也就是說你希望每做一次改動就執行一次測試,而不是在每次發布版本之前或基于每日的基礎版本執行測試。
測試執行的越頻繁,你從中得到的信息就越多。
你等待測試執行的時間越短,你經常執行它們的意愿就越高。簡而言之,如果想要頻繁的執行測試,那么測試代碼執行的速度就必須要快,快到無可復加!
整個測試執行通過的時間應該限制在 1 秒之內,而不是 10 秒,更不能是 1 分鐘。
這意味著你:
- 要在 Java 虛擬機(JVM)上執行測試,而不能是在設備上
- 要只測試獨立的業務邏輯單元
- 不要將 UI、數據庫和網絡測試包含在你的主測試套件中
- 不要在測試中使用 wait/sleep 語句
2. 編寫小而專的測試
要始終記得編寫測試是為了找出問題。也就是說你需要明確設計測試用例的目的是為了捕獲應用中的 bug。
假如應用中有一個 bug,你更喜歡哪種測試結果:
一個 bug -> 多條測試失敗
一個 bug -> 只有一條測試失敗
當然是第二個!因為這樣比較容易調試。當一個測試失敗時,你可以根據測試名稱來查看哪里出了問題。
@Test
public void logInShouldFailWithWrongPassword() throws Exception {
// Test code
}
每一個 bug 必須只有一個對應的測試失敗。失敗的原因需要用測試名來描述。
這樣會強制你針對每個測試只檢查一個點,并且會保持測試足夠小而更容易理解,解釋和維護。
這也是為什么一個好的測試應該像我們代碼庫中的其他方法一樣,小(只有幾行代碼)而專(只測一個點)。
要做到這一點,你需要:
- 在每條測試只包含一條斷言/驗證語句
- 將少量的大測試拆解為大量的小測試
- 在測試名中明確描述失敗的原因
3. 100% 的可靠性
測試是程序的安全保障,所以你需要認真對待失敗的測試。你需要放下手頭所有的事情去解決問題。
想象一下,程序在你急切的想要添加一個新特性時突然出現了問題,而你不得不放下當前工作去修復出現的問題。這是多么令人沮喪的事情啊!!!
再想一下,如果你花費了幾個小時的時間去分析問題,沒有任何頭緒,(絕望中)又執行了一次測試,所有的測試都通過了...
對開發者而言,最沮喪的事情莫過于浪費時間在那些清理一下工程或重啟一下 IDE 就被修復的隨機錯誤。
如果多個測試都是這樣的原因導致的,你會對整個測試套件失去信任。你不再認真對待失敗的測試,也將不再從整個測試套件中得到任何幫助。
這也是為什么你要保持測試 100% 的可靠性,并且只在真正出現問題時使測試失敗。
要做到這一點,你需要:
- 在 JVM 上運行測試(與設備的連接可能會斷開)
- 在測試中模擬網絡交互
- 將 UI/集成測試移出單元測試套件
總結
測試執行的越頻繁,你從中得到的信息就越多。好的單元測試依賴于足夠快、專,并且可靠性足夠高。
<iframe frameborder="no" border="0" marginwidth="0" marginheight="0" width=330 height=86 src="http://music.163.com/outchain/player?type=2&id=436514312&auto=1&height=66"></iframe>