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

 什麼是Mock

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

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

 

在一個項目裏, 咱們常常須要把某一部分程序獨立出來以便咱們能夠對這部分進行測試. 這就要求咱們不要考慮項目其他部分的複雜性, 咱們只想關注須要被測試的那部分. 這裏就須要用到模擬(Mock)技術.github

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

綠色的是須要被測試的類, 黃色Mock的依賴項數據庫

 

Mock技術帶來的優勢

使用Mock技術, 能夠有以下的優勢:編程

  • 提升測試運行速度, 例如能夠模擬DB, Web Service等比較慢的服務, 以及算法等.
  • 支持並行開發, 例如實際的依賴項尚未完成開發, 或者等待其餘團隊開發依賴項.
  • 提升測試可靠性, 例若有時這個依賴項的bug太多了, 常常因爲依賴項的緣由致使測試失敗, 那麼就應該使用mock版原本驗證咱們本身寫的代碼.
  • 減小開發/測試成本, 有時程序可能依賴一些雲服務, 這些服務是按調用次數收費的, 那麼就可使用Mock版原本節省這方面的開資, 固然了最後仍是須要使用真正的服務測試才行; 有時候組建依賴項太費勁了, 就用mock版本吧, 省時省力.
  • 在有不肯定性依賴項的狀況下進行測試, 有些依賴項有不肯定性, 可能無理由的形成測試失敗, 這時候就應該使用mock版本的依賴.

 

單元測試

Mock技術一般在單元測試中使用, 可使用xUnit來爲.NET Core應用作單元測試, 這裏有介紹xUnit的文章: http://www.javashuo.com/article/p-rqwpmfqu-gm.html框架

那麼什麼是一個單元? 函數

這個一般是由團隊對系統的理解決定, 能夠針對一個類, 也能夠針對多個類.單元測試

單元測試一般具備如下特色:測試

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

 

術語

  • 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的第一篇先到這.

相關文章
相關標籤/搜索