在 xunit 測驗專案中使用依賴注入
Intro
之前寫過幾篇 xunit 依賴注入的文章,今天這篇文章將結合我在 .NET Conf 上的分享,更加系統的分享一下在測驗中的應用案例,
之所以想分享這個話題是因為我覺得在我們開發程序中測驗是非常重要的一部分,高質量專案的一個重要指標就是測驗覆寫率,同時依賴注入已經是一個現代化應用中不可缺少的一部分,我們的 .NET Core 也是從一開始就集成了依賴注入,依賴注入對于測驗專案也是不能缺席的,
xunit 是 .net 里目前使用的最多的測驗組件,Xunit.DependencyInjection 是大師寫的一個 xunit 依賴注入的擴展,它是基于微軟的 GenericHost(通用主機) 來實作的,使用它我們可以很輕松的實作依賴注入,很好的和 .NET Core 做集成,
How it works
那它是如何作業的呢?我們一起來看一下它的執行流程,它的執行流程分為四步
首先需要構建一個 Host,然后啟動這個 Host,啟動完成后執行測驗用例,最后終止這個 Host

Host 又是如何構建的呢?我們一起看一下,Host 的構建也是分為四步
第一步,創建一個 HostBuilder,大多數情況下我們不需要用這個方法,使用默認的實作就好
第二步,Host 配置,對 Host 做一些自定義配置
第三步,服務配置,注冊需要的服務
第四步,Configure,可以做一些初始化的配置,比如配置初始化以及測驗資料的初始化等

我們可以在測驗專案里創建一個 Startup 類來控制 Host 的構建程序
示例
接著我們來看一些實際的測驗示例,示例分為三部分,首先是一些基本用法,然后是和其他組件的集成,最后是一些擴展用法

Get Started
首先來看一下 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 使用,來看一下這個示例

IoC/AOP Integration
接著我們來看一下和其他組件的集成,AutoFac 是一個很流行的 IOC 組件,AspectCore 是檸檬大佬寫的一個 AOP 框架,我們以這兩個為例子來看一下如何集成第三方的依賴注入和 AOP 組件,前面我們已經提到它是基于微軟的 GenericHost 實作的,而 asp.net core 從 3.0 開始也是基于 GenericHost 實作的,所以在 asp.net core 里怎么集成,在這里也是一樣的,來看一下示例,只需要使用對應的 ServiceProviderFactory 就可以了,是不是很簡單呢


Test Server Integration
然后我們來看一下如何和 TestServer 做集成,TestServer 主要用于集成測驗,使用 TestServer 的好處在于它是基于記憶體進行互動的沒有真正的 HTTP 請求和 TCP 鏈接,會非常的高效,而且也不會監聽某一個埠,所以不會有埠權限的問題,
TestServer 的使用主要有兩步,首先是服務的注冊,可以使用 IHostBuilder 或 IWebHostBuilder 的 UseTestServer 擴展方法注冊 TestServer,可以使用 IHost 的 GetTestClient 擴展方法來注冊和 TestServer 進行互動的 HttpClient
服務注冊好之后就可以在測驗用例里通過注入的 HttpClient 請求 API 或頁面了,可以參考這個例子

Extensions
Hosted Service
然后我們來看一些擴展用法,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 邏輯
ITestOutputHelperAccessor
在測驗中如果想要輸出一個日志的話只能借助于 ITestOutputHelper 來輸出,直接使用 Console.Write[Line] 是看不到任何輸出的,ITestOutputHelper 只能在測驗用例中使用,在測驗服務中是不能使用的,Xunit.DependencyInjection 提供了一個 ITestOutputHelperAccessor 的服務,類似于 IHttpContextAccessor,我們可以借助它來在自定義的服務中獲取 ITestOutputHelper 來輸出日志
這里是一個簡單的示例

Logging
再來看一個 OutputHelperAccessor 的實際應用,Xunit.DependencyInjection 提供了一個 Logging 的擴展,使得我們可以把測驗程序中的日志輸出出來,更好的幫助我們除錯
集成方式也比較簡單,可以參考這個示例,參考 Xunit.DependencyInjection.Logging 之后,在 LoggerFactory 中注冊 XunitTestOutputLoggerProvider 即可
可以看到我們的日志直接輸出出來了,默認的日志級別是 Information ,所以 Debug 級別的日志沒有輸出出來,有需要的話可以在注冊的時候提供一個委托來控制是否要輸出日志

Project Template
為了方便大家使用,我們提供了一個專案模板,可以通過一個命令就可以直接創建好一個測驗專案,會包含一個默認的 Startup 不再需要自己去寫方法了,使用的時候只需要根據需要做刪減就可以了
默認的 TargetFramework 使用的是 netcoreapp3.1,可以通過 -f/--franework 指定自己想要使用的目標框架,比如說想要生成 net 5.0 的專案只需要指定 -f net5.0 就可以了

生成的內容如下所示:

More
最后列出來了一些可能會有幫助的鏈接,第一個是專案的源代碼,第二個是 PPT 中所有示例的源代碼,后面的是使用到的 Nuget 包,
這個 xunit 擴展的代碼實作是非常值得學習的,有很多和 asp.net core 的實作是很像的,有需要的可以去看看原始碼學習一下,
希望我的分享對大家有所幫助,大家在使用程序中有遇到任何問題都可以隨時聯系我或者直接在 Github 上建 issue,
Reference
- https://github.com/pengweiqhca/Xunit.DependencyInjection
- https://github.com/WeihanLi/XunitDependencyInjection.Samples
- https://www.nuget.org/packages/Xunit.DependencyInjection
- https://www.nuget.org/packages/Microsoft.AspNetCore.TestHost
- https://www.nuget.org/packages/Xunit.DependencyInjection.Logging
- https://www.nuget.org/packages/Xunit.DependencyInjection.Template
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/240726.html
標籤:.NET Core
