測試 ASP.NET Core API Controller


本文需要您了解ASP.NET Core MVC/Web API, xUnit以及Moq相關知識.

這里有xUnit和Moq的介紹: https://www.cnblogs.com/cgzl/p/9178672.html#test

 

Controllers可以說是ASP.NET Core MVC/Web API項目的核心, 它們把整個應用都整合到了一起. 可以說Controllers是非常重要的, 所以我們應該對它們做一些測試.

由於我幾乎只做API, 所以本文不包括關於MVC功能的測試, 只包括Controller的API相關功能.

 

測試一個簡單的Controller

先舉一個簡單點的例子:

這個Controller相對簡單, 它有一個依賴項.

它一個方法, 返回類型是IActionResult, 又具體分為兩種情況.

測試返回結果的類型

首先需要new出來一個被測試的RootController, 標准的叫法叫System Under Test(被測試系統). 它需要一個urlHelper作為依賴項, 那就Mock一個即可.

每組測試數據都會走一遍構造函數的.

該測試方法使用的是Theory, 用了4組數據. 執行方法后返回的結果類型應該實現了IActionResult接口, 這里可以用Assert.IsAssignableFrom<TExpected>(actual)來判斷.

注: 為了方便, 我使用了resharper.

測試之前一定要重新Build一下.

然后再點擊resharper在方法旁邊提供的測試按鈕即可:

從圖可以看出resharper提供了方便快捷的圖標, 在這你可以選擇運行或者調試測試.

 

測試會通過的, Theory下屬的4組數據將被視為4個單獨的測試:

 

針對該方法的其它測試

我又添加了兩個測試方法, 來測試該方法的不同路徑及返回結果:

 

通常一個測試方法里應該只有一個Assert. 但是第二方法里面有兩個Assert, 這是因為這兩個Assert都是測試的同一個行為, 所以我認為這樣應該是可以的.

 

Rebuild, 測試:

也是OK的.

 

看起來針對RootController的GetRoot()方法, 我們好像已經測試了所有可執行的路徑. 讓我們使用測試代碼覆蓋率這個功能來確定一下.

點擊resharper在測試類旁邊提供的CoverAll按鈕:

隨后會出現單元測試窗口和覆蓋率窗口.

 

直接看覆蓋率窗口:

可以看到該Controller和方法的覆蓋率都是100%了.

 

來到被測試的RootController里:

Resharper(實際上是dotCover) 在代碼的左邊顯示出了該行代碼是否已經被測試覆蓋, 如果都是綠色的就說明都被覆蓋了.

 

導出覆蓋率結果

Resharper的代碼覆蓋率結果可以導出多種格式:

 

例如導出HTML后也可以查看覆蓋率明細:

 

測試復雜一點的Controller

 

這個ProductController略微復雜一點, 首先它需要很多依賴項.

 

看它的POST Action方法, 很多地方需要被測試:

 

測試ModelState

首先可以測試product為null的情況, 但是這個太簡單了, 我就不啰嗦了.

那就測試ModelState.Invalid情況吧:

為了讓ModelState Invalid, 我手動添加了ModelState的error. 和被測試方法其它必要的參數.

該方法有三個Assert, 首先判定結果類型是否為UnprocessableEntityObjectResult(422狀態碼), 然后再判定返回結果包含了ModelState的error.

該測試會pass, 並會覆蓋這部分相關的代碼:

 

測試特定方法會被調用

這里需要使用moq了, 為了讓被測試方法順利跑完, 我設定Mock版的UnitOfWork的SaveAsync()方法會返回true, (注意這個方法的返回類型是Task<bool>):

然后通過moq的Verify()方法判定repository的AddProduct()和unitOfWork的SaveAsync()方法分別被調用了.

 

Build, 測試會pass, 覆蓋率目前比較大了(但是覆蓋率100%並不能說明代碼沒問題):

 

模擬SaveAsync()后的實體數據

該項目使用的是EFCore, 在_unitOfWorkSaveAsync()之后, 變量productModel的Id就會有非0值了, 也就是說productModel在_unitOfWorkSaveAsync()方法執行之后發生了變化.

針對這種情況, 我們可以使用moq的Callback()功能:

剛開始為autoMapper的兩次map動作設定了返回值.

然后在UnitOfWork的SaveAsync()執行后有個Callback()回調, 回調時相當於模擬了EFCore的保存, 把最新的值賦給了productModel(看被測試代碼), (其實這里不用Callback也行....).

隨后就是一系列的Assert, 判定某些方法是否執行, 返回類型是否正確, 返回的數據是否正確等.

 

Build 測試會通過的:

 

其它路徑的測試

目前該方法還有兩處地方沒有被覆蓋:

 

可以再寫兩個測試來覆蓋它們:

這兩個很簡單, 不多介紹了, 注意這里使用了async版本的Assert.Throws().

 

這兩個測試會pass, 最終該方法的代碼覆蓋率就達到100%了:

 

ASP.NET Core Web API Controller的測試就介紹這些吧.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM