攜程大牛的單元測試是怎麼樣寫的?

你們都知道,開發軟件的時候爲代碼編寫單元測試是很好的。但實際上,光有測試還不夠,還要編寫好的測試,這一樣重要。python

要作到這一點,考慮遵循一些執拗的原則,對測試代碼給予一些關愛:正則表達式

1. 保持測試代碼的緊湊和可讀性

要作到這一點,應該要進行絕不留情的重構,就像對生產代碼應該作的那樣。不然讓測試代碼隨着時間腐化,就是在測試裏面製造可怕的遺留代碼。若是測試不能很容易重構,那麼生產代碼也很難重構,從而致使生產系統的遺留代碼。始終作一個勇敢的重構者。編程

2. 避免編寫重複累贅的斷言

舉個例子,測試代碼使用正則表達式生成內容,而這個正則表達式是跟生產代碼的解析器中使用的如出一轍的。工具

通常來講,咱們不但願在測試和代碼之間複製邏輯。所以,在測試中複製正則表達式或其餘內容不是一種選擇。在這種狀況下,考慮測試輸入激勵/輸出結果之間的關係(f(輸入) - >輸出)可能會有幫助,例如,若是代碼的目標是要作模板替換,不要在測試代碼裏用原始值來作替換。相反,在測試裏面直接指定預期的計算結果。單元測試

// 使用
Assertions.assertThat(processTemplate("param1", "param2")).isEqualTo("this is 'param1', and this is 'param2'"));

// 而不要用
Assertions.assertThat(processTemplate("param1", "param2")).isEqualTo("this is '%s', and this is '%s'", param1, param2));

  

3. 覆蓋儘量多的範圍,包括正面狀況,以及(甚至更重要的)出錯的代碼路徑。

一般,要作到這一點,最好的辦法試採用測試驅動開發(Test Driven Development)。經過TDD,人們能夠在設計時識別可能會出錯的部分。不要羞於爲一段小代碼編寫一個簡單的測試用例。你永遠不知道何時,爲何以及以什麼方式,你會要用到甚至修改這段代碼。測試

 

能夠研究一下如何檢查測試的有效性,相似PIT這樣的工具能夠進行變動測試,值得研究一下。this

4. 不要Mock你不擁有的類型!

這不是一個硬界限,但越過這條線極可能會產生副作用力!插件

TDD是關於設計的,也是關於測試的,二者同樣重要,在模擬外部API時,測試不能用於驅動設計,API屬於第三方;這個第三方能夠,而且實際上也常常會更改API的簽名和行爲。設計

想象一下Mock第三方Lib的代碼。在第三方庫的某次升級以後,它的邏輯可能會改變,但測試套件仍會執行得很好,由於它被Mock了。因此後來,你認爲一切都很好,畢竟構建牆是綠色的,軟件部署上去,而後......嘣對象

若是你感受須要Mock第三方庫,可能代表你當前的設計與第三方庫沒有足夠的分離。

另外一個問題是第三方庫可能很複雜,須要大量的Mock才能正常工做。這致使過分指定的測試和複雜的測試輔助裝置,這自己就損害了緊湊和可讀的目標。或者因爲模擬外部系統過於複雜,從而致使測試代碼對生產代碼的覆蓋不足。

取而代之的最多見的方法,是圍繞外部lib / 系統建立包裝器,儘管應該意識到抽象泄漏的風險,其中過多的低級API,概念或異常超出了包裝器的邊界。爲了驗證與第三方庫的集成,編寫集成測試,並使它們儘量緊湊和可讀。

5. 不要Mock一切,這是一種反模式

若是一切都被Mock,咱們真的在測試生產代碼嗎?該不Mock的時候,不要猶豫!

不要Mock值對象

爲何人們甚至想要這樣作?

由於實例化對象太痛苦了! => 不是正當理由。

若是建立新的對象太難了,那麼代碼可能須要一些嚴肅的重構。另外一種方法是爲您的值對象建立構建器 - 有一些工具,包括IDE插件,Lombok和其餘。還能夠在測試類路徑中建立有意義的工廠方法。

abstract class CustomerCreations {
   public static Customer customer_with_a_single_item_in_the_basket() {
       // long init sequence
   }
}

  Mockito專一於對象之間的相互操做,這是面向對象編程的核心部分。

相關文章
相關標籤/搜索