天天看點

單元測試(三)-模拟對象

前面使用了樁對象來解除被測代碼對外部的依賴,以便于獨立地測試代碼的内部邏輯。但樁對象隻能測試系統的傳回值或者狀态的改變,如果要測試對象之間的互動,則需要使用模拟對象。

1 三種測試類型

a) 三種類型的測試分别為:

Value-based testing測試方法的傳回值

State-based testing 測試狀态的改變

Interaction testing 測試對象之間的互動

b) 互動測試測試的是某種特定的行為(如給另一個對象傳遞資訊)。作者認為,互動測試應該盡量少用,在能使用值測試和狀态測試的場合,就不要使用互動測試,因為互動測試會增加複雜度

c) 用自動給植物澆水的裝置舉例來說明狀态測試與互動測試的差別:狀态測試就是在一天結束後,通過檢視土壤中的水分、植物的生長情況來測試澆水效果;而互動測試則要實時記錄澆水次數、水量等資訊。狀态測試得出結論需要一定的過程和準備工作;但互動測試實施起來卻不友善

d)  樁對象用于值測試和狀态測試,模拟對象則用于互動測試

2 樁對象與模拟對象的差別

模拟對象是一種可以記錄對自身調用情況的僞對象。模拟對象可用于互動測試,可認為是在樁對象的基礎上,增加了記錄調用情況的功能。它們之間的差別如下:

a) 樁對象(stub)替代被測代碼對第三方對象的依賴,然後要針對被測代碼進行斷言

單元測試(三)-模拟對象

b) 模拟對象(mock)則模拟第三方依賴,然後為了判斷被測代碼是否與第三方依賴正确互動,要針對模拟對象進行斷言

單元測試(三)-模拟對象

c) 模拟對象可以讓測試失敗,但樁對象不會

3 模拟對象的應用

a) 還是使用之前的LogAnalyzer類,假設業務場景為:當檔案名稱太短時,調用web服務發送資訊。但web服務是外部依賴,web傳輸也比較費時,而且現在測試的是LogAnalyzer對web服務的調用行為(互動)。

LogAnalyzer如下

單元測試(三)-模拟對象

在測試代碼中,将FakeWebService對象作為模拟對象傳遞給LogAnalyzer,并要針對FakeWebService對象進行斷言。

單元測試(三)-模拟對象

在模拟對象中,屬性LastError會記錄上一次互動的内容以供斷言

單元測試(三)-模拟對象

b) stub和mock有時需要同時使用,比如測試場景改為:調用WebService時可能會發生異常,如果有異常,則發送郵件給管理者,測試要做的是觀察發送郵件行為是否正确。

LogAnalyzer比上一個的複雜

單元測試(三)-模拟對象

在測試代碼中,FakeWebService作為樁對象,FakeEmailService作為模拟對象,首先設定FakeWebService要抛異常,最後針對FakeEmailService記錄的郵件内容進行斷言,測試LogAnalyzer與其的互動是否正确

單元測試(三)-模拟對象

可以設定FakeWebService是否要抛異常

單元測試(三)-模拟對象

FakeEmailService作為模拟對象,與上一個例子中FakeWebService的職責類似,記錄互動資訊以供斷言

單元測試(三)-模拟對象

以上便是stub與mock的差別,以及mock的基本使用方法,在第二個例子中,同時使用了stub與mock,最後針對mock進行斷言,這也是mock使用的基本原則,一個測試中最多隻能有一個mock,其它都為stub;mock存在時便隻對mock斷言;在一個測試中隻應該驗證一件事,如果有多個mock意味着在測試不止一件事。

參考資料:

The Art of Unit Testing with examples in

C#, 2nd Edition by Roy Osherove