一個外部依賴項是系統(tǒng)中的一個對象秉颗,被測試代碼與這個對象發(fā)生交互痢毒,但不能控制這個對象(不能控制這個對象返回值;不能控制這個對象的具體行為蚕甥;對象還未實現(xiàn))哪替。常見的依賴包括系統(tǒng)時間、Web服務(wù)菇怀、文件系統(tǒng)凭舶、數(shù)據(jù)庫服務(wù)晌块、內(nèi)存等。如何破除這些外部依賴帅霜,如何與他們進(jìn)行交互測試就是本篇文章討論的主要內(nèi)容匆背。
使用Stub破除依賴
Stub可以看做是一個依賴項的 ** 可控制 **的替代物,即偽造的對象身冀。利用Stub钝尸,使被測試代碼可以得到所有需要的輸入,獨立地測試了代碼邏輯闽铐。破除依賴首先需要找到被測試工作單元使用的外部接口蝶怔,然后把這個接口的底層實現(xiàn)替換成Stub。這里的『替換』就是我們常說的『依賴注入』兄墅,下面介紹幾種常見的依賴注入方法踢星。
- 構(gòu)造函數(shù)注入
使用這種方法,需要給被測試類添加一個新的構(gòu)造函數(shù)(或者給已有的構(gòu)造函數(shù)添加一個新參數(shù))隙咸,參數(shù)傳入Stub沐悦,然后在被測試類眾添加一個局部字段用于保存Stub,供被測試方法使用五督。 - 用屬性get或set注入
這里需要為每個要注入的依賴項添加一個屬性get和set藏否,然后在被測試代碼中需要的地方使用這些依賴。 - 從工廠類返回給被測試代碼依賴項
首先讓被測試的工作單元使用工廠類返回的對象實例充包,然后測試代碼中配置該工廠類副签,讓它返回一個Stub。 - 偽造工廠類
實現(xiàn)自定義的工廠類基矮,該自定義的工廠類返回一個Stub淆储,然后把這個偽工廠類賦給被測試的工作單元。 - 繼承被測試類
繼承被測試類家浇,重寫其虛工廠方法本砰,使其返回Stub。
使用Mock進(jìn)行交互測試
在上一篇『單元測試之如何編寫優(yōu)秀的單元測試用例』中钢悲,我們了解了工作單元有三種最終結(jié)果:返回值点额、內(nèi)部狀態(tài)改變、調(diào)用第三方對象莺琳』估猓基于值的測試驗證了一個函數(shù)的返回值;基于狀態(tài)的測試改變被測試對象的狀態(tài)芦昔,然后驗證其可見的狀態(tài)變化诱贿;交互測試則是驗證一個對象如何向其他對象發(fā)送消息的測試。實際單元測試中,優(yōu)先考慮基于值珠十、基于狀態(tài)的測試方法料扰,因為這兩種測試可以減少對代碼內(nèi)部細(xì)節(jié)的假設(shè)。
Mock是系統(tǒng)中一個偽造的對象焙蹭,它可以驗證被測試對象是否按照預(yù)期的方式調(diào)用了這個偽對象晒杈。Mock與Stub都是偽對象,但是使用Stub時孔厉,Stub只是輔助測試運(yùn)行拯钻,單元測試代碼仍然是對工作單元進(jìn)行斷言;使用Mock時撰豺,Mock對象會記錄所有工作單元與其進(jìn)行的通訊粪般,單元測試代碼是對Mock對象進(jìn)行斷言,用來檢驗交互污桦。
隔離框架應(yīng)運(yùn)而生
前面介紹了Stub和Mock在單元測試中的重要作用亩歹,但是如果使用手工的Stub和Mock會出現(xiàn)一些缺陷:
- 如果類或者接口有很多方法、屬性凡橱,那么就很難為其編寫Stub和Mock對象
- Mock對象需要記錄所有工作單元與其通訊的信息小作,手工編寫工作量大且易出錯
- 難以在其他測試中重用Stub和Mock對象
隔離框架是一套API,使用這套API可以在運(yùn)行時創(chuàng)建和配置偽對象稼钩。下面介紹隔離框架常見功能:
- 動態(tài)生成偽對象(Stub顾稀、Mock)
- 模擬返回值和異常
- 參數(shù)匹配
- 驗證方法調(diào)用次數(shù)
使用隔離框架,會讓我們得單元測試變得更加輕松坝撑,幫助我們編寫更加易讀静秆、易維護(hù)、更可靠的測試代碼巡李。