使用 Moq 測試.NET Core 應用 - Why Moq?

来源:https://www.cnblogs.com/cgzl/archive/2018/07/12/9294431.html
-Advertisement-
Play Games

什麼是Mock 當對代碼進行測試的時候, 我們經常需要用到一些模擬(mock)技術. 綠色的是需要被測試的類, 黃色是它的依賴項, 灰色的無關的類 在一個項目里, 我們經常需要把某一部分程式獨立出來以便我們可以對這部分進行測試. 這就要求我們不要考慮項目其餘部分的複雜性, 我們只想關註需要被測試的那 ...


 什麼是Mock

當對代碼進行測試的時候, 我們經常需要用到一些模擬(mock)技術.

綠色的是需要被測試的類, 黃色是它的依賴項, 灰色的無關的類

 

在一個項目里, 我們經常需要把某一部分程式獨立出來以便我們可以對這部分進行測試. 這就要求我們不要考慮項目其餘部分的複雜性, 我們只想關註需要被測試的那部分. 這裡就需要用到模擬(Mock)技術.

因為, 請仔細看. 我們想要隔離測試的這部分代碼對外部有一個或者多個依賴. 所以編寫測試代碼的時候, 我們需要提供這些依賴. 而針對隔離測試, 並不應該使用生產時用的依賴項, 所以我們使用模擬版本的依賴項, 這些模擬版依賴項只能用於測試時, 它們會使隔離更加容易.

綠色的是需要被測試的類, 黃色Mock的依賴項

 

Mock技術帶來的優點

使用Mock技術, 可以有如下的優點:

  • 提高測試運行速度, 例如可以模擬DB, Web Service等比較慢的服務, 以及演算法等.
  • 支持並行開發, 例如實際的依賴項還沒有完成開發, 或者等待其他團隊開發依賴項.
  • 提高測試可靠性, 例如有時這個依賴項的bug太多了, 經常由於依賴項的原因導致測試失敗, 那麼就應該使用mock版本來驗證我們自己寫的代碼.
  • 減少開發/測試成本, 有時程式可能依賴一些雲服務, 這些服務是按調用次數收費的, 那麼就可以使用Mock版本來節省這方面的開資, 當然了最後還是需要使用真正的服務測試才行; 有時候組建依賴項太費勁了, 就用mock版本吧, 省時省力.
  • 在有不確定性依賴項的情況下進行測試, 有些依賴項有不確定性, 可能無理由的造成測試失敗, 這時候就應該使用mock版本的依賴.

 

單元測試

Mock技術通常在單元測試中使用, 可以使用xUnit來為.NET Core應用做單元測試, 這裡有介紹xUnit的文章: https://www.cnblogs.com/cgzl/p/9178672.html#xunit

那麼什麼是一個單元? 

這個通常是由團隊對系統的理解決定, 可以針對一個類, 也可以針對多個類.

單元測試通常具有以下特點:

  • 低級別
  • 高聚焦
  • 執行速度快
  • 容易測試所有執行路徑上的代碼

 

術語

  • Test Double (我認為可以翻譯為測試替身), 是所有非真實依賴項的總稱.
    • Fake, Fake是那種可以正常工作的實現, 儘管可以正常工作, 但是它們不可以用於生產環境, 例如EFCore里的記憶體資料庫提供商.
    • Dummy, 有時候, 被測試方法需要一些參數, 但是這些參數實際上並沒有用到, 這時就可以創建dummy, 它們的存在只是為了滿足調用方法的參數要求.
    • Stub, (狀態測試). 它可以使用很直接的方式模擬依賴項的行為. 例如我們可以使用Stub把相關數據放到記憶體里查詢而不是查詢真實的資料庫; 如果某個測試類需要依賴項的某個Property的值, 那麼stub就設定這個值就行.
    • Mock, (行為/交互測試). 與Stub不同的是, Mock期待的不是返回值, Mock期待的是動作的執行. 它是依賴項的動態包裝, 它可以對哪個方法以什麼樣的順序被待測試系統(SUT)調用的這個期待行為進行預編程. 也就是說被測試的系統只有按照特定的順序調用mock依賴項的特定方法, 那麼該系統才算測試通過.

還有其它的一些術語就不介紹了, 主要是這四個.

對於Stub 和 Mock ,可以看下麵兩張圖例:

 

Moq

官網: https://github.com/moq/moq4

Moq框架可以用來創建dummy, stub 和 mock. 在本文里把這三個東西都叫做mock對象吧.

Moq使用一套API來創建stub和mock對象.

 

準備項目

一個簡單的.NET Core控制台項目: https://github.com/solenovex/Moq-Tutorial-Code, 代碼是裡面的01 before.

該項目非常簡單, 是關於球員轉會業務, 它目前只有三個類. 

TransferApplication, 球員轉會申請類:

TransferResult, 轉會審批結果枚舉:

 

還有TransferApproval, 轉會審批類:

'

當前的邏輯是, 發起球員轉會申請後, 進行審批: 如果總費用大於預算, 那麼就直接拒絕; 如果總費用不超標, 並且球員小於30歲, 那麼就批准; 但如果球員大於30歲, 並且是超級巨星的話, 這將由老闆決定.

 

建立單元測試項目

在解決方案里建立一個xUnit類型的項目:

 

然後要保證該項目所用到的庫都保持最新:

 

最後別忘了添加對FootballManager項目的引用:

 

打開Text Explorer, 可以看到裡面有一個待測的單元測試:

 

做一個簡單的單元測試

把UnitTest1改成下麵這個簡單的單元測試:

重新Build後, 可以看到單元測試的名稱更新了.

 

點擊Run All, 運行單元測試, 結果成功:

 

隨後再添加一個簡單的單元測試:

 

Build, 後就會出現這個測試:

 

Run All, 測試也會成功:

 

添加依賴

這時, 有一些需求的變化, 球員轉會審批前, 需要通過體檢.

首先在轉會申請類裡面添加兩個球員的屬性:

 

然後添加一個體檢的介面:

這兩個方法的作用是一樣的, 但是調用方法略有不同.

 

但是此時, 該介面的實現類還沒有開發完畢:

 

在轉會審批類裡面, 需要添加這個依賴, 使用的是介面:

 

在單元測試類裡面, 我為轉會球員添加了這兩個屬性, 但是審批類會報錯, 因為沒有加入依賴項:

 

所以測試的時候需要註入這個依賴項IPhysicalExamination, 但是PhysicalExamination類還沒有做完(裡面的方法都沒有實現), 所以我們無法new出來這個類.

這時, 我們也許可以傳null進去?

 

這時, 項目是不報錯了.

跑單元測試, Run All:

測試失敗, 拋出NullReferenceException. 而這個異常導致了測試無法正常進行.

 

所以, 我們需要Moq, 它可以提供一個Mock(模擬)版本的IPhysicalExamination, 並把它傳遞到審批類的構造函數里.

 

安裝Moq

在單元測試項目添加Moq:

 

Moq的第一篇先到這.

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 日子過得真快,又是想念你們的一天呢,今天也要記得微笑哦!!很久沒有玩adobe的東西了,這幾天摸魚一下,手感已經生疏了,以前還打算一直學習下去,後來慢慢轉變成了在合成上面的興趣了呢,我知道很醜啦,所以只是在學習前的日常扯皮嘛,好啦好啦,開始學習了。 上次講到了一小部分的裝飾器,現在我們接著開始複習, ...
  • Description 給你一個無向圖,N(N<=500)個頂點, M(M<=5000)條邊,每條邊有一個權值Vi(Vi<30000)。給你兩個頂點S和T,求 一條路徑,使得路徑上最大邊和最小邊的比值最小。如果S和T之間沒有路徑,輸出”IMPOSSIBLE”,否則輸出這個 比值,如果需要,表示成一個 ...
  • 在做響應式頁面的時候,往往需要考慮更多尺寸設備的界面相容性,一般不能寫死像素,以便能夠使得界面元素能夠根據設備的不同進行動態調整,但往往有時候還是碰到一些問題,如Tab標簽第一頁面正常顯示,但是切換其他頁面的時候顯示內容沒有發生動態的調整,本篇隨筆介紹解決Tab標簽頁切換圖表顯示問題,以及圖表控制項可... ...
  • 前提題要:因為我最近負責的Winfrom項目,好多都用到了這個log4net的日誌功能,開發程式對數據一般都要求做到雁過留痕,所以日誌對於我們程式員是不可或缺。因此我把對log4net的使用做一個記錄總結,以便於以後的使用記憶。l 一、概述 log4net是.Net下一個非常優秀的開源日誌記錄組件。 ...
  • Dictionary和hashtable用法有點相似,他們都是基於鍵值對的數據集合,但實際上他們內部的實現原理有很大的差異, 先簡要概述一下他們主要的區別,稍後在分析Dictionary內部實現的大概原理。 區別: 1. Dictionary支持泛型,而Hashtable不支持。 2. Dictio ...
  • 群里一小伙伴在開發APP時遇到了問題,便截圖提問 一、傻瓜式解決辦法: 刪除: ((System.ComponentModel.ISupportInitialize)(this.performanceCounter1)).EndInit(); 這個辦法雖然簡單,但是會出錯。 原因是,當你添加perf ...
  • OfflineCameraButton控制項 一、 樣式一 我們要實現上圖中的效果,需要如下的操作: 設置控制項的背景色,預設設置為“White”,如圖1; 圖 1 設置控制項背景色透明度,預設設置為“255”,即不透明,如圖2; 圖 2 若將該屬性設置為“0”,該控制項的背景色即為全透明的,顯示為Smob ...
  • C#5.0推出了新語法,await與async,但相信大家還是很少使用它們。關於await與async有很多文章講解,但有沒有這樣一種感覺,你看完後,總感覺這東西很不錯,但用的時候,總是想不起來,或者不知道該怎麼用。 為什麼呢?我覺得大家的await與async的打開方式不正確。 正確的打開方式 首 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...