以前寫過幾篇 xunit 依賴注入的文章,今天這篇文章將結合我在 .NET Conf 上的分享,更加系統的分享一下在測試中的應用案例。git
之因此想分享這個話題是由於我以爲在咱們開發過程當中測試是很是重要的一部分,高質量項目的一個重要指標就是測試覆蓋率,同時依賴注入已是一個現代化應用中不可缺乏的一部分,咱們的 .NET Core 也是從一開始就集成了依賴注入,依賴注入對於測試項目也是不能缺席的。github
xunit 是 .net 裏目前使用的最多的測試組件,Xunit.DependencyInjection
是大師寫的一個 xunit 依賴注入的擴展,它是基於微軟的 GenericHost
(通用主機) 來實現的,使用它咱們能夠很輕鬆的實現依賴注入,很好的和 .NET Core 作集成。web
那它是如何工做的呢?咱們一塊兒來看一下它的執行流程,它的執行流程分爲四步app
首先須要構建一個 Host,而後啓動這個 Host,啓動完成後執行測試用例,最後終止這個 Host框架
Host 又是如何構建的呢?咱們一塊兒看一下,Host 的構建也是分爲四步asp.net
第一步,建立一個 HostBuilder
,大多數狀況下咱們不須要用這個方法,使用默認的實現就好ide
第二步,Host 配置,對 Host 作一些自定義配置學習
第三步,服務配置,註冊須要的服務測試
第四步,Configure
,能夠作一些初始化的配置,好比配置初始化以及測試數據的初始化等ui
咱們能夠在測試項目裏建立一個 Startup
類來控制 Host
的構建過程
接着咱們來看一些實際的測試示例,示例分爲三部分,首先是一些基本用法,而後是和其餘組件的集成,最後是一些擴展用法
首先來看一下 Startup
的用法,這個 Startup
和 asp.net core 裏的 Startup
是很像的,不管是使用方式上仍是實現上都是相似的,有興趣的能夠看一下源碼對比一下,咱們來看一下使用方式,經過下面的示例來感覺一下
若是你只須要註冊服務,直接在 Startup
中添加一個 ConfigureServices
方法,在這個方法中註冊本身須要的服務便可,和 asp.net core 並沒有太多不一樣
若是你須要作一些初始化的工做,能夠加一個 Configure
方法,在這個方法中實現本身的初始化邏輯就能夠了,若是初始化的時候須要獲取注入的服務實例,直接做爲方法參數就能夠,相似於 asp.net core 中 Configure
方法,只是不須要配置 Http 請求管道
若是你須要使用的配置,須要使用 Configuration,能夠在 ConfigureHost
方法中經過 ConfigureHostConfiguration
擴展方法註冊本身的配置
若是須要在註冊服務的時候用到配置,能夠在 ConfigureServices
方法中添加一個 HostBuildContext
的參數,HostBuilderContext
中的 Configuration
對象就是在 ConfigureHost
中註冊的配置
若是須要在 Configure
方法中使用配置,直接添加一個 IConfiguration
的方法參數就能夠了
咱們再來看一下,如何在測試用例中使用注入的服務,通常狀況下咱們會直接經過構造器注入,在構造方法中添加須要注入的服務便可,除此以外咱們還能夠經過方法參數注入,結合 InlineData
和 MemeberData
使用,來看一下這個示例
接着咱們來看一下和其餘組件的集成,AutoFac
是一個很流行的 IOC 組件,AspectCore
是檸檬大佬寫的一個 AOP 框架,咱們以這兩個爲例子來看一下如何集成第三方的依賴注入和 AOP 組件,前面咱們已經提到它是基於微軟的 GenericHost
實現的,而 asp.net core 從 3.0 開始也是基於 GenericHost
實現的,因此在 asp.net core 裏怎麼集成,在這裏也是同樣的,來看一下示例,只須要使用對應的 ServiceProviderFactory
就能夠了,是否是很簡單呢
而後咱們來看一下如何和 TestServer
作集成,TestServer
主要用於集成測試,使用 TestServer
的好處在於它是基於內存進行交互的沒有真正的 HTTP 請求和 TCP 連接,會很是的高效,並且也不會監聽某一個端口,因此不會有端口權限的問題。
TestServer
的使用主要有兩步,首先是服務的註冊,可使用 IHostBuilder
或 IWebHostBuilder
的 UseTestServer
擴展方法註冊 TestServer
,可使用 IHost
的 GetTestClient
擴展方法來註冊和 TestServer
進行交互的 HttpClient
服務註冊好以後就能夠在測試用例裏經過注入的 HttpClient
請求 API 或頁面了,能夠參考這個例子
而後咱們來看一些擴展用法,IHostedService
能夠用來實現一些初始化的操做或者後臺服務,咱們可使用 IHostedService
來實現對應用的 Ready 檢查,應用 Ready 以後再開始執行測試用例,這在有些場景下是頗有用的
咱們在 k8s 中部署的應用通常都會有一個 HealthCheck
/ReadinessCheck
的接口來供 k8s 的 liveness/readiness 探針來探測應用的狀態,只有應用 Ready 以後纔會對外部提供服務
這個示例就是一個使用 IHostedService
來實現等待應用 Ready 後再開始執行測試用例的一個 demo
注意:這裏的等待不能在
Startup
的Configure
方法中執行,由於Configure
的執行是在調用 Host 的StartAsync
方法以前執行的,而此時 webServer 尚未啓動,因此是不能獲取到TestClient
的,而咱們經過HostedService
就能夠在 Web Server 啓動以後再執行咱們的等待 Ready 邏輯
在測試中若是想要輸出一個日誌的話只能藉助於 ITestOutputHelper
來輸出,直接使用 Console.Write[Line]
是看不到任何輸出的,ITestOutputHelper
只能在測試用例中使用,在測試服務中是不能使用的,Xunit.DependencyInjection
提供了一個 ITestOutputHelperAccessor
的服務,相似於 IHttpContextAccessor
,咱們能夠藉助它來在自定義的服務中獲取 ITestOutputHelper
來輸出日誌
這裏是一個簡單的示例
再來看一個 OutputHelperAccessor
的實際應用,Xunit.DependencyInjection
提供了一個 Logging 的擴展,使得咱們能夠把測試過程當中的日誌輸出出來,更好的幫助咱們調試
集成方式也比較簡單,能夠參考這個示例,引用 Xunit.DependencyInjection.Logging
以後,在 LoggerFactory
中註冊 XunitTestOutputLoggerProvider
便可
能夠看到咱們的日誌直接輸出出來了,默認的日誌級別是 Information
,因此 Debug
級別的日誌沒有輸出出來,有須要的話能夠在註冊的時候提供一個委託來控制是否要輸出日誌
爲了方便你們使用,咱們提供了一個項目模板,能夠經過一個命令就能夠直接建立好一個測試項目,會包含一個默認的 Startup
再也不須要本身去寫方法了,使用的時候只須要根據須要作刪減就能夠了
默認的 TargetFramework
使用的是 netcoreapp3.1
,能夠經過 -f
/--franework
指定本身想要使用的目標框架,好比說想要生成 net 5.0 的項目只須要指定 -f net5.0
就能夠了
生成的內容以下所示:
最後列出來了一些可能會有幫助的連接,第一個是項目的源代碼,第二個是 PPT 中全部示例的源代碼,後面的是使用到的 Nuget 包。
這個 xunit 擴展的代碼實現是很是值得學習的,有不少和 asp.net core 的實現是很像的,有須要的能夠去看看源碼學習一下。
但願個人分享對你們有所幫助,你們在使用過程當中有遇到任何問題均可以隨時聯繫我或者直接在 Github 上建 issue。