單元測試及最佳實踐


前言

鏡子迷宮

在工作中或者在面試中,我經常碰到的開發人員就是對單元測試不重視,這一類基本上都表現出了一種“無知的自信”,總覺得自己寫的代碼質量很高,直到一次次蟲子(Bug)把自己咬的頭破血流時,才發現原來自己的代碼已經到了剪不斷理還亂的狀態,而每一次修改一個bug,都需要走一遍“墨鏡迷宮” (看上圖)。還有很多人知道單元測試或者寫出了單元測試,但是就是寫了一個方法,上面標注了一個[Test]屬性而已,甚至很多的人單元測試上面標注的是[IgnoreTest], 每次看見這些,我都深深的感到推行單元測試之路是艱難的,是遙遠的,但是我依然堅信是是渴望也可及的,只要有着深深的信念,堅強的意志,無謂的勇氣,一頭扎進去泥巴堆里,假以時日,當大雨來臨,必將帶走泥巴,從此你拔劍揚眉,哦,你不用拔劍了,因為你就是劍。。。

為了讓更多人能夠拔劍揚眉,也為了我們公司剛入職的新人做一些培訓,我精心准備了單元測試的一些知識,在此為你奉上,我盡量用簡短的語句來描述,如果你不清楚我說的某一些點,那么歡迎你發郵件給我 wangdeshui@outlook.com,我可以針對集中的點發篇文章,如果你想知道我說的所有點怎么實踐,那就聯系我,試試加入到我們公司來。

什么是單元測試

單元測試是開發者編寫的一小段代碼,用於檢驗被測代碼中的一個很明確的功能是否正確。通常而言,一個單元測試是用於判斷某個特定條件(或者場景)下某個特定函數的行為。

執行單元測試,是為了證明某段代碼的行為確實和開發者所期望的一致。因此,我們所要測試的是規模很小的、非常獨立的功能片段。通過對所有單獨部分的行為建立起信心。然后,才能開始測試整個系統。

為什么要使用單元測試

  • 單元測試使工作完成的更輕松
  • 單元測試使你的設計更好
  • 大大減少花在調試上的時間
  • 能幫助你更好的理解代碼

沒有單元測試

  • 任何代碼都是在假定其他代碼是正確無誤的情況下編寫的。
  • 修改一處代碼時無法得知會對其他代碼產生怎樣的影響。
  • 任何一處改動都需要進行功能級別的整體調試。

單元測試難以推動的原因

太花時間

很多人認為單元測試很花時間,但是想想我們在下面幾點話的時間,我經常看到為了測試一個簡單的API方法,我們很多人必須讓前端跑起來,甚至自己寫一個客戶端才能調用

  • 調試上花的時間
  • 對自認為正確的代碼,花了多少時間確認代碼是正確的。
  • 定位Bug所耗的時間

測試不是我的工作

很多人認為測試不是自己的工作,但是想一想每次測試提出一個bug所花的時間,以及你改bug所化的時間,所以下面2點是很重要

  • 內在質量的重要性
  • 測試應該是輔助,好的軟件是開發設計出來的,不是測試出來的

系統可測試性差

  • 系統耦合度很高,我們需要提高我們的團隊的設計能力。

單元測試最佳實踐

實踐一: 三到五步

  • SetUp
  • 輸入
  • 調用
  • 輸出
  • TearDown

實踐二: 運行快速

為什么?

單元測試運行很頻繁,是輔助開發的,在開發過程中運行,如果慢影響很大

多快較好?

  • 單個測試小於200ms
  • 單個測試套件小於10s
  • 整個測試小於10分鍾

實踐三:一致性

任何時候同樣的輸入需要同樣的結果

    Date date=new Date()
    Random.next()

這樣的代碼都需要Mock掉,不然時間每次都不同,結果就會不一樣。

實踐四:原子性

** 所有的測試只有兩種結果:成功和失敗**
不能部分測試通過

實踐五:單一職責

一個測試只驗證一個行為

** 測試行為,不要測試方法 **

  • 一個方法,多個行為    ----->  多個測試
  • 一個行為,多個方法   -----   一個測試
    這里的一個行為,多個方法一般指這個方法調用private, protected, getters, setters
  • 多個Assert只有在測試同一個行為時可以接受

實踐六:獨立無耦合

單元測試之間無相互調用

  • 單元測試執行順序無關
  • 不同的順序無影響

單元測試之間不能共享狀態

比如一個測試里設置了一個屬性值,然后在另外一個測試里用,如果必須共享可以放到Setup里

實踐七:隔離外部調用

  • 單元測試需要快速運行,且每次結果一致,所以需要隔離一切對外部的調用。
  • 不使用具體的其它真實類,就是不要new
  • 不讀數據庫
  • 不讀網絡
  • 不讀外部文件
  • 適當時候可以構造一個相同的內部文件來Mock
  • 不依賴本地時間
  • 不依賴環境變量

實踐八: 自描述

  • 單元測試是開發級文檔
  • 單元測試是方法的描述
    單元測試自描述命名

實踐九: 單元測試邏輯

  • 單元測試必須容易讀和理解的
  • 變量名,方法名,類名
  • 無條件語句,無Switch
    辦法:分解if到多個測試,所有的輸入都是已知的,所有的結果都是一定的(Mock)
  • 無循環語句
  • 無異常捕捉
    ** 測試預知的異常,用ExpectedException方法 **

實踐十: 斷言

  • 斷言信息最好包含Business Information

  • 斷言信息包含出錯的具體信息如果失敗

  • 適當時候可以封裝自己的Assert
    比如:

    Assert.IsProgrammer(Jack)
    Return Jack. Cancooking() && Jack.CanCoding()
    

實踐十一:產品代碼

  • 產品代碼無測試邏輯
    不能有:

If(global.IsTest){…}

  • 測試代碼和產品代碼要分離
  • 不要在產品代碼里有任何只供測試用的代碼
  • 使用依賴注入

最后,單元測試常用技術及工具

下面是.NET程序常用的單元測試需要的技術和工具,其它語言請自信比對。

  • 面向接口編程
  • 依賴注入(Castle, Unity, Ninject)
  • Moq
  • 測試工具(xUnit)
  • .Net Nunit
  • 代碼覆蓋率測試工具Ncover
  • 自動運行測試輔助工具NCrunch


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM