簡體   English   中英

Mocking的用途

[英]The Purpose of Mocking

mocking 的用途是什么?

我一直在關注一些 ASP.NET MVC 教程,這些教程使用 NUnit 進行測試,使用 Moq 進行 mocking。不過我對其中的 mocking 部分不太清楚。

mocking的作用是為了將被測試的class與其他類隔離

這在 class 時很有用:

  • 連接到外部資源(文件系統、數據庫、.網絡...)
  • 設置昂貴,或尚不可用(正在開發硬件)
  • 減慢單元測試的執行
  • 具有不確定的行為
  • 有(或是)用戶界面

它還可以更輕松地測試錯誤條件,因為您構建模擬 object 以便它返回並出錯,拋出異常...

mock 可以記錄它是如何被調用的(函數調用順序、參數),這可以通過測試來驗證。 編輯:例如:您正在測試的方法發送一條消息,例如 IPC。 mock object 的方法可以記錄它被調用了多少次,他收到的參數(即要發送的消息)。 然后測試可以詢問模擬 object 並斷言發送的消息數量、消息的內容...同樣,模擬 object 可以記錄在日志字符串中調用的方法,測試可以檢索該字符串並斷言在上面。

不要濫用模擬對象:測試行為而不是實現,否則單元測試將與代碼緊密耦合,並且很脆弱(在重構時中斷)。

Mock 可以手動編碼,也可以由mocking 框架生成。

Mocking 允許您將被測 class 與其依賴項隔離開來。 通常,您為被測 class 的每個依賴項創建一個模擬,並設置模擬以返回預期值。 然后,您向被測 class 提供模擬,而不是被測 class 所依賴的 class 的真實副本。 然后,您可以使用 mocking 框架來檢查是否對模擬對象進行了預期的調用,以確保被測 class 正常運行。

它旨在取笑一組集合中的單個實例。 在不定期的 object 聚會上用的很多。

雖然 mocking 通常被理解為允許隔離被測 class,但這不是模擬的要點(存根對此更好)。 相反,我們需要看看當 object 被告知做某事時會發生什么,這是三件事之一..

  1. 直接 Output - 方法調用的結果
  2. 內部更改 - 在方法調用期間對 class 的更改
  3. 間接 Output - 被測代碼調用不同的 class

基於 State 的測試都是關於#1 和#2 的。 #1 通過查看該方法給你的結果。 #2 通過訪問內部對象 state。

這給我們留下了#3,我們可以采取兩種途徑。 第一個是使用 Mock,第二個是使用 Test Spy。 主要區別在於,在 Mock 上,您在執行被測代碼之前創建期望,然后讓模擬驗證它們,而在 Test Spy 上,您執行被測代碼,然后詢問 Test Spy 是否發生了某些操作。

所以總結一下.. 當你考慮測試 class 的作用時,如果你需要測試間接 output(也就是調用另一個類),這就是 Mocking 發揮作用的地方。

我也是 mocking 的新手,但我會嘗試一下。 根據我的經驗,mocking 有兩個主要好處:

  • 您可以在實際編寫實現之前開始使用對象。 您可以定義一個接口並使用 mocking 在單元測試甚至代碼中使用該接口。
  • Mocking 允許您在單元測試中隔離被測 object。 使用模擬對象,您可以完全控制被測 object 與之交互的任何對象,從而從測試中消除外部依賴性。

“模擬”在測試和 TDD 圈子中是一個重載的術語。 請參閱 Martin Fowler 的文章Mocks Aren't Stubs 一個“適當的”模擬知道它應該接收什么值,並在它沒有得到預期的值時讓您知道; 這允許您進行交互測試而不是 state 測試 - 您驗證被測 class 是否以正確的順序將正確的消息傳遞給它的合作者。 交互測試與傳統的 state 測試有很大不同,可能很難理解。 請記住,交互測試是模擬的重點可能會使它們更容易理解。

另一個答案:

  • Stub = 能夠在沒有整個真實上下文的情況下運行測試的假對象

  • Mock = fake object 記錄組件的交互並驗證這些交互

你可以在一個測試中有多個存根,但只有一個模擬,因為如果你有多個模擬,你肯定會測試多個功能(並且它違背了測試一件事原則的目的)。

對於超越基礎知識的 go,Mocks 比傳統的 state 測試驗證更多的行為驗證,在測試中,您在對它執行操作后檢查組件的 state(Arrange,Act,Assert with Mocks 它更多 Arrange,Act,Verify):

State驗證Assert.AreEqual(valueExpected,mycomponent.Property); 行為驗證:myMock.WasCalled(MyMethod);

Bert F的 Mocking 的實時示例

單元測試

想象一下這個系統的單元測試:

cook <- waiter <- customer

通常很容易設想測試像cook這樣的低級組件:

cook <- test driver

測試司機只需點不同的菜,並驗證廚師為每個訂單返回正確的菜。

更難測試中間組件,比如服務員,它利用了其他組件的行為。 天真的測試人員可能會像測試 cook 組件一樣測試 waiter 組件:

cook <- waiter <- test driver

測試司機會點不同的菜,並確保服務員返回正確的菜。 不幸的是,這意味着對服務員組件的測試可能依賴於廚師組件的正確行為。 如果 cook 組件有任何測試不友好的特征,這種依賴性會更糟,比如不確定的行為(菜單包括廚師的驚喜作為一道菜),很多依賴性(廚師沒有他的全體員工就不會做飯),或者很多資源(有些菜餚需要昂貴的原料或需要一個小時來烹飪)。

由於這是服務員測試,理想情況下,我們只想測試服務員,而不是廚師。 具體來說,我們要確保服務員正確地將客戶的訂單傳達給廚師,並將廚師的食物正確地送到客戶手中。

單元測試意味着獨立測試單元,因此更好的方法是使用Fowler 所說的測試替身(假人、存根、假貨、模擬)來隔離被測組件(服務員)

    -----------------------
   |                       |
   v                       |
test cook <- waiter <- test driver

在這里,測試廚師與測試駕駛員“勾結”。 理想情況下,被測系統被設計成可以很容易地替代(注入)測試廚師與服務員一起工作,而無需更改生產代碼(例如,無需更改服務員代碼)。

模擬對象

現在,測試廚師(測試替身)可以用不同的方式實現:

  • 假廚師 - 使用冷凍食品和微波爐冒充廚師的人,
  • 一個小廚師——無論你點什么,總是給你熱狗的熱狗供應商,或者
  • 模擬廚師 - 一名卧底警察按照劇本假裝是一名廚師進行誘捕行動。

請參閱Fowler 的文章,了解有關假貨、存根、模擬物和假人的更多細節,但現在,讓我們關注模擬廚師。

    -----------------------
   |                       |
   v                       |
mock cook <- waiter <- test driver

單元測試 Waiter 組件的很大一部分集中在 Waiter 如何與 Cook 組件交互。 基於模擬的方法側重於完全指定正確的交互是什么,並檢測它何時出錯。

模擬 object 預先知道在測試期間應該發生什么(例如,它的哪些方法調用將被調用等)並且模擬 object 知道它應該如何反應(例如提供什么返回值)。 模擬將指示實際發生的情況是否與應該發生的情況不同。 自定義模擬 object 可以針對每個測試用例的預期行為進行編碼,但 mocking 框架力求讓此類行為規范能夠在測試用例中直接明確且輕松地指示。

圍繞基於模擬的測試的對話可能如下所示:

模擬廚師試車手期待熱狗訂單並給他這個虛擬熱狗作為回應

試駕(冒充顧客)對服務員我要熱狗
服務員模擬廚師請來一份熱狗
服務員模擬廚師點單:准備好 1 個熱狗(將虛擬熱狗交給服務員)
服務員試駕員這是你的熱狗(給試駕員假人熱狗)

測試驅動程序:測試成功!

但由於我們的服務員是新來的,所以可能會發生以下情況:

模擬廚師試車手期待熱狗訂單並給他這個虛擬熱狗作為回應

試駕(冒充顧客)對服務員我要熱狗
服務員模擬廚師請給我 1 個漢堡包
模擬廚師停止測試:有人告訴我要點熱狗!

測試驅動程序注意到問題:TEST FAILED! - 服務員改變了訂單

要么

模擬廚師試車手期待熱狗訂單並給他這個虛擬熱狗作為回應

試駕(冒充顧客)對服務員我要熱狗
服務員模擬廚師請來一份熱狗
服務員模擬廚師點單:准備好 1 個熱狗(將虛擬熱狗交給服務員)
服務員試駕這是你的炸薯條(把其他訂單的炸薯條給試駕)

測試司機注意到意想不到的炸薯條:測試失敗! 服務員退錯菜了

如果沒有與 go 對比的基於存根的示例,可能很難清楚地看到模擬對象和存根之間的區別,但是這個答案已經太長了:-)

另請注意,這是一個非常簡單的示例,mocking 框架允許對組件的預期行為進行一些非常復雜的規范,以支持全面的測試。 有關模擬對象和 mocking 框架的大量資料可提供更多信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM