不管如何組織測試,不管有多少測試,若是你不能信任、維護以及閱讀它們,這些測試就幾乎沒有價值。要成爲優秀的測試,它們應該同時具備以下三個屬性。安全
測試代碼與產品代碼同樣須要不斷進行維護,一旦測試寫好了而且經過了,一般是不該該修改或刪除這些測試的。這些測試是你的保護網告訴你修改的代碼是否破壞了已有的功能。雖然說如此,有時可能仍是須要修改或者刪除已有的測試。要理解什麼狀況下修改或刪除測試會帶來問題,什麼狀況下這麼作是合理的。
刪除一個測試的主要的理由是這個測試失敗了。若是一個測試忽然開始失敗,可能有以下緣由多線程
若是測試或代碼沒有任何問題,修改或刪除測試的緣由有:函數
不可讀的測試帶來的麻煩比解決的問題更多。它會影響代碼的可讀性,妨礙你理解測試發現的問題
若是你看到測試名含義不清或者使人誤解,或者測試的可維護性有待提升,就應該修改測試代碼(可是不要改變測試的基本功能)單元測試
若是單元測試中有下列任何一種語句,你的測試就包含了不該該有的邏輯:*學習
包含邏輯的測試一般會一次測試多個東西,咱們不推薦這種作法,由於這樣的測試可讀性較也比較脆弱。並且測試邏輯也增長了代碼複雜度,可能包含隱藏的缺陷一般來講,一個單元測試應該是一系列的方法調用和斷言,可是不包含控制流語句,甚至不該將斷言語句包含在try- catch中。任何更復雜的語句均可能致使以下問題。測試
如前所述,一個關注點是一個工做單元的一個最終結果:一個返回值、系統狀態的一個改變或者對第三方對象的一個調用。例如:若是你的單元測試對多個對象進行了斷言,那麼這個測試有可能測試了多個關注點。另外一種狀況是,它既測試了一個對象返回正確的值,又驗證系統狀態改變致使這個對象的行爲發生變化,那麼這個測試也可能測試了多個關注點。
測試多個關注點聽起來沒什麼,可是等到你要命名測試,或者考慮第一個對象的斷言失敗該如何處理時,就會遇到問題。
命名測試看似簡單,可是若是同時測試了多個東西,就幾乎不可能給測試起一個能說明測試內容的好名字。你最後起的名字可能很是通用,使得讀者不得不去閱讀測試代碼(本章的可讀性節詳細對此進行討論)。若是一次只測試一個關注點,測試命名就很簡單線程
把集成混在單元測試裏放在測試項目中會致使不少方面的問題。這種測試難以運行,會讓人們誤覺得代碼有問題,浪費時間和精力進行檢查,最後致使開發人員再也不信任這組測試。混在單元測試裏的集成測試就像筐裏的爛蘋果連累了其餘的測試。若是下一次再發生相似的事情,開發人員甚至都不會去調查失敗緣由,直接就說:「哦,那個測試有時候就是會失敗,沒事的。」要避免這樣的事情發生,就要建一個綠色安全區把集成測試和單元測試分開。
綠色安全區裏只包含單元測試。運行綠色安全區裏的全部測試測試結果應該所有是綠色的,若是有測試失敗,就說明出現了真正的代碼問題,而不是由於某些配置或外部依賴倒置的假警報。code
代碼覆蓋率100%說明什麼呢?若是沒有作代碼審查,這個覆蓋率不能說明什麼。你的團隊可能會要求全部人的測試「達到95%以上的代碼覆蓋率」,你們可能也確實作到了。可是也許這些測試連斷言都沒有。人們一般會選擇作最少的事情達到某個指定的目標。
那麼代碼覆蓋率100%再加上測試和代碼審查能說明什麼呢?這說明整個世界都是你的。若是你作了代碼審查和測試審查,確保測試優秀並且覆蓋了全部代碼,那麼你就擁有了一個安全網,能夠避免愚蠢的錯誤,同時團隊也得到了分享的知識,從持續的學習中獲益對象
做爲開發者,單元測試中的重複代碼和產品代碼中的重複同樣(若是不是更加)有害。DRY原則應該一樣適用於測試代碼。重複代碼意味測試對象某方面改變時要修改更多的測試代碼。若是測試中有大量重複代碼,構造函數變動或者使用類的語義變化會產生極大的影響內存
測試隔離的基本概念是:一個測試應該老是在它本身的小世界中運行,與其餘進行相似或不一樣的工做的測試隔離甚至不知道其餘測試的存在。
若是沒有很好地隔離測試,它們會互相影響,使你很是悲慘,後悔在項目中嘗試單元測試決心之後不再作單元測試了。我見過這種狀況。開發人員不肯費心檢查測試中的問題,所以當出現問題時,須要花不少時間才能找到緣由有些測試一樣存在着一些壞味道可以提示測試隔離可能有問題。
Assert.AreEqual(2,Sum(1,2)); Assert.AreEqual(5,Sum(2,2)); Assert.AreEqual(6,Sum(5,2));
如上示例,這個測試方法中使用了三個斷言,進行了三個測試。這樣看起來在實際過程當中會節省一些寫代碼的時間,但會有一些問題。若是第一個斷言失敗,則後續斷言就不會在執行。而在這個示例中咱們是進行了三個測試。第一個斷言失敗就會致使咱們沒法得知另外兩個測試的測試結果。對於這種狀況咱們能夠採起別的方式進行測試
過分指定的測試對一個具體的被測試單元如何實現其內部行爲進行了假設,而不是隻檢查其最終行爲的正確性單元測試中過分指定主要有如下幾種狀況
不可讀的測試幾乎沒有任何意義。可讀性這條線鏈接着編寫測試的人和幾個月後閱讀測試的人。測試是你向項目的下一代開發者講述的故事,幫助開發者理解一個應用程序的組成及其開端。
測試可讀性有以下幾個方面
命名標準很是重要,提供了合理的規則和模板,列出應該包括的測試信息。測試名通常包括三部分。
public void IsValidFileName(){ ... } [Test] public void IsValidFileName_WhenPNG_ReturnFalse(){ ... }
如上示例,經過測試的方法命名咱們就能夠大概知道要測試的是方法是IsValidFileName當輸入參數是PNG的時候,預期返回False。
固然,你的團隊也能夠有適合本身的命名方式,但重要的是若是一個團隊中都有統一的有意義命名規範,那麼單元測試的可讀性將大大提高,而且有利於後來者快速進入項目,理解測試。
測試中的變量命名和產品代碼中的命名規範一樣重要,經過合理的變量命名,咱們能夠確保閱讀測試的人能夠儘快的理解你要驗證什麼。
// 反例 Assert.AreEqual(100,actual);
如上示例,咱們常常會看到測試中出現"100"這樣的魔法數字。由於測試中沒有描述性的名字,也許你在剛剛寫完的時候還知道它是什麼意思,可是一週後,一月後,一年後呢?甚至你將來的繼任者看到這樣的測試代碼也是一頭霧水。
不少人爲了「偷懶」常常會把斷言和方法調用卸載同一行裏,但這是一個很很差的習慣,它會大大下降代碼的可讀性。
// 反例 Assert.AreEqual(true,fileManger.IsValidName()) // 正例 bool expect=true; bool actual=fileManger.IsValidName(); Assert.AreEqual(expect,actual)