單元測(cè)試及最佳實(shí)踐

前言

鏡子迷宮

在工作中或者在面試中,我經(jīng)常碰到的開(kāi)發(fā)人員就是對(duì)單元測(cè)試不重視,這一類基本上都表現(xiàn)出了一種“無(wú)知的自信”,總覺(jué)得自己寫的代碼質(zhì)量很高,直到一次次蟲(chóng)子(Bug)把自己咬的頭破血流時(shí),才發(fā)現(xiàn)原來(lái)自己的代碼已經(jīng)到了剪不斷理還亂的狀態(tài),而每一次修改一個(gè)bug,都需要走一遍“墨鏡迷宮” (看上圖)。還有很多人知道單元測(cè)試或者寫出了單元測(cè)試,但是就是寫了一個(gè)方法,上面標(biāo)注了一個(gè)[Test]屬性而已,甚至很多的人單元測(cè)試上面標(biāo)注的是[IgnoreTest], 每次看見(jiàn)這些,我都深深的感到推行單元測(cè)試之路是艱難的,是遙遠(yuǎn)的,但是我依然堅(jiān)信是是渴望也可及的,只要有著深深的信念,堅(jiān)強(qiáng)的意志,無(wú)謂的勇氣,一頭扎進(jìn)去泥巴堆里,假以時(shí)日,當(dāng)大雨來(lái)臨,必將帶走泥巴,從此你拔劍揚(yáng)眉,哦,你不用拔劍了,因?yàn)槟憔褪莿?。?!?/p>

為了讓更多人能夠拔劍揚(yáng)眉,也為了我們公司剛?cè)肼毜男氯俗鲆恍┡嘤?xùn),我精心準(zhǔn)備了單元測(cè)試的一些知識(shí),在此為你奉上,我盡量用簡(jiǎn)短的語(yǔ)句來(lái)描述,如果你不清楚我說(shuō)的某一些點(diǎn),那么歡迎你發(fā)郵件給我 wangdeshui@outlook.com,我可以針對(duì)集中的點(diǎn)發(fā)篇文章,如果你想知道我說(shuō)的所有點(diǎn)怎么實(shí)踐,那就聯(lián)系我,試試加入到我們公司來(lái)。

什么是單元測(cè)試

單元測(cè)試是開(kāi)發(fā)者編寫的一小段代碼,用于檢驗(yàn)被測(cè)代碼中的一個(gè)很明確的功能是否正確。通常而言,一個(gè)單元測(cè)試是用于判斷某個(gè)特定條件(或者場(chǎng)景)下某個(gè)特定函數(shù)的行為。

執(zhí)行單元測(cè)試,是為了證明某段代碼的行為確實(shí)和開(kāi)發(fā)者所期望的一致。因此,我們所要測(cè)試的是規(guī)模很小的、非常獨(dú)立的功能片段。通過(guò)對(duì)所有單獨(dú)部分的行為建立起信心。然后,才能開(kāi)始測(cè)試整個(gè)系統(tǒng)。

為什么要使用單元測(cè)試

  • 單元測(cè)試使工作完成的更輕松
  • 單元測(cè)試使你的設(shè)計(jì)更好
  • 大大減少花在調(diào)試上的時(shí)間
  • 能幫助你更好的理解代碼

沒(méi)有單元測(cè)試

  • 任何代碼都是在假定其他代碼是正確無(wú)誤的情況下編寫的。
  • 修改一處代碼時(shí)無(wú)法得知會(huì)對(duì)其他代碼產(chǎn)生怎樣的影響。
  • 任何一處改動(dòng)都需要進(jìn)行功能級(jí)別的整體調(diào)試。

單元測(cè)試難以推動(dòng)的原因

太花時(shí)間

很多人認(rèn)為單元測(cè)試很花時(shí)間,但是想想我們?cè)谙旅鎺c(diǎn)話的時(shí)間,我經(jīng)常看到為了測(cè)試一個(gè)簡(jiǎn)單的API方法,我們很多人必須讓前端跑起來(lái),甚至自己寫一個(gè)客戶端才能調(diào)用

  • 調(diào)試上花的時(shí)間
  • 對(duì)自認(rèn)為正確的代碼,花了多少時(shí)間確認(rèn)代碼是正確的。
  • 定位Bug所耗的時(shí)間

測(cè)試不是我的工作

很多人認(rèn)為測(cè)試不是自己的工作,但是想一想每次測(cè)試提出一個(gè)bug所花的時(shí)間,以及你改bug所化的時(shí)間,所以下面2點(diǎn)是很重要

  • 內(nèi)在質(zhì)量的重要性
  • 測(cè)試應(yīng)該是輔助,好的軟件是開(kāi)發(fā)設(shè)計(jì)出來(lái)的,不是測(cè)試出來(lái)的

系統(tǒng)可測(cè)試性差

  • 系統(tǒng)耦合度很高,我們需要提高我們的團(tuán)隊(duì)的設(shè)計(jì)能力。

單元測(cè)試最佳實(shí)踐

實(shí)踐一: 三到五步

  • SetUp
  • 輸入
  • 調(diào)用
  • 輸出
  • TearDown

實(shí)踐二: 運(yùn)行快速

為什么?

單元測(cè)試運(yùn)行很頻繁,是輔助開(kāi)發(fā)的,在開(kāi)發(fā)過(guò)程中運(yùn)行,如果慢影響很大

多快較好?

  • 單個(gè)測(cè)試小于200ms
  • 單個(gè)測(cè)試套件小于10s
  • 整個(gè)測(cè)試小于10分鐘

實(shí)踐三:一致性

任何時(shí)候同樣的輸入需要同樣的結(jié)果

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

這樣的代碼都需要Mock掉,不然時(shí)間每次都不同,結(jié)果就會(huì)不一樣。

實(shí)踐四:原子性

** 所有的測(cè)試只有兩種結(jié)果:成功和失敗**
不能部分測(cè)試通過(guò)

實(shí)踐五:?jiǎn)我宦氊?zé)

一個(gè)測(cè)試只驗(yàn)證一個(gè)行為

** 測(cè)試行為,不要測(cè)試方法 **

  • 一個(gè)方法,多個(gè)行為 -----> 多個(gè)測(cè)試
  • 一個(gè)行為,多個(gè)方法 ----- 一個(gè)測(cè)試
    這里的一個(gè)行為,多個(gè)方法一般指這個(gè)方法調(diào)用private, protected, getters, setters
  • 多個(gè)Assert只有在測(cè)試同一個(gè)行為時(shí)可以接受

實(shí)踐六:獨(dú)立無(wú)耦合

單元測(cè)試之間無(wú)相互調(diào)用

  • 單元測(cè)試執(zhí)行順序無(wú)關(guān)
  • 不同的順序無(wú)影響

單元測(cè)試之間不能共享狀態(tài)

比如一個(gè)測(cè)試?yán)镌O(shè)置了一個(gè)屬性值,然后在另外一個(gè)測(cè)試?yán)镉茫绻仨毠蚕砜梢苑诺絊etup里

實(shí)踐七:隔離外部調(diào)用

  • 單元測(cè)試需要快速運(yùn)行,且每次結(jié)果一致,所以需要隔離一切對(duì)外部的調(diào)用。
  • 不使用具體的其它真實(shí)類,就是不要new
  • 不讀數(shù)據(jù)庫(kù)
  • 不讀網(wǎng)絡(luò)
  • 不讀外部文件
  • 適當(dāng)時(shí)候可以構(gòu)造一個(gè)相同的內(nèi)部文件來(lái)Mock
  • 不依賴本地時(shí)間
  • 不依賴環(huán)境變量

實(shí)踐八: 自描述

  • 單元測(cè)試是開(kāi)發(fā)級(jí)文檔
  • 單元測(cè)試是方法的描述


    單元測(cè)試自描述命名

實(shí)踐九: 單元測(cè)試邏輯

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

實(shí)踐十: 斷言

  • 斷言信息最好包含Business Information

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

  • 適當(dāng)時(shí)候可以封裝自己的Assert
    比如:

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

實(shí)踐十一:產(chǎn)品代碼

  • 產(chǎn)品代碼無(wú)測(cè)試邏輯
    不能有:

     If(global.IsTest){…}
    
  • 測(cè)試代碼和產(chǎn)品代碼要分離

  • 不要在產(chǎn)品代碼里有任何只供測(cè)試用的代碼

  • 使用依賴注入

最后,單元測(cè)試常用技術(shù)及工具

下面是.NET程序常用的單元測(cè)試需要的技術(shù)和工具,其它語(yǔ)言請(qǐng)自信比對(duì)。

  • 面向接口編程
  • 依賴注入(Castle, Unity, Ninject)
  • Moq
  • 測(cè)試工具(xUnit)
  • .Net Nunit
  • 代碼覆蓋率測(cè)試工具Ncover
  • 自動(dòng)運(yùn)行測(cè)試輔助工具NCrunch
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容