ASP.NET Core擴展庫之Http請求模擬功能的使用
如今,完全獨立的業(yè)務應用幾乎不存在,不管是在企業(yè)內(nèi)部微服務之間的調(diào)用,還是與外部第三方服務的調(diào)用,Http的API交互是常見的場景,這些實際情況給我們的開發(fā)帶來了比較大的挑戰(zhàn),一是第三方服務可能會牽制我們的開發(fā)進度,特別是在多團隊開發(fā)的情況下,由于依賴于其他團隊的服務,有時候需要等待其他團隊的進度,導致自己團隊的無效等待。有時因為其他團隊的延期,導致團隊的被動延期。二是第三方服務的質(zhì)量問題或開發(fā)過程中的頻繁更新導致的部署問題,將嚴重拖累自己團隊的開發(fā)進度,同時讓你無法專心的開發(fā)自己的服務。三是單元測試困難,特別是在依賴于多個第三方服務時,使得單元測試可能依賴于其他服務環(huán)境,導致單元測試結(jié)果的不確定性。
為了解決以上這些問題,Xfrogcn.AspNetCore.Extensions擴展庫提供了Http請求模擬的功能,通過此功能可以讓你在開發(fā)、單元測試時實現(xiàn)你的服務與第三方服務的完全解耦,讓你能夠更聚焦于自己服務的開發(fā)。
Http請求模擬構(gòu)建在.NET Core HttpClientFactory架構(gòu)之上,通過在HttpClient請求管道中替換實際發(fā)送Http請求的主消息處理器為模擬消息處理器來完成請求的模擬應答。
一、在服務端使用
假設(shè)我們負責開發(fā)一個訂單服務,在訂單提交接口,我們保存完訂單數(shù)據(jù)之后,需要發(fā)送消息通知,消息通知的發(fā)送由消息服務來實現(xiàn),該服務由另一團隊負責,如下圖所示:
由于訂單服務依賴于消息服務,在項目啟動時,一般兩個團隊會協(xié)商好消息服務的接口定義,然后消息服務團隊會快速搭建一個空接口供訂單服務團隊調(diào)用,如果是這種流程,訂單服務團隊只需等待消息服務團隊搭建好環(huán)境即可開始工作,好像影響不大,但在實際開發(fā)過程中,會存在以下現(xiàn)實的問題:
- 雖然消息服務團隊提供空接口的時間不長,但是如果項目工期緊張,計劃都是以小時計算,那么這也將影響訂單服務的開發(fā)進度
- “空消息服務”實際上無法一直保持空的狀態(tài),消息服務團隊會不斷對服務進行更新加入他們的實現(xiàn)邏輯,而消息服務本身也可能依賴于其他的服務,這導致訂單團隊所使用的消息服務不穩(wěn)定,那么訂單團隊的進度實際上還是會受到消息服務團隊,以及消息服務所依賴的其他團隊的影響。
- 訂單服務團隊可以使用空的消息服務,但消息服務團隊往往需要連接企業(yè)外部的第三方服務,比如App的消息推送通道,這讓整個項目依賴更加復雜。
- 訂單服務團隊編寫單元測試會比較困難(當然,此點可以通過抽象來解決,但結(jié)合擴展庫的Http請求模擬功能,我們可以簡化此過程)
以下介紹如何使用擴展庫的請求模擬功能。
為了聚焦于模擬功能的演示,該示例進行了簡化,比如與消息服務的通訊,在正式項目中會通過消息服務的SDK來完成,示例中將直接使用HttpClient,有關(guān)SDK與擴展庫的結(jié)合,我們將在后續(xù)文章中說明。
1.引用Xfrogcn.AspNetCore.Extensions
2.定義訂單類
public class Order { public string Id { get; set; } public string ProductCode { get; set; } public decimal Price { get; set; } public int Quantity { get; set; } public decimal Amount { get; set; } }
3.定義消息發(fā)送請求類
public class SendMessageRequest { public string MessageId { get; set; } public string Message { get; set; } public List<int> UserIds { get; set; } }
4.配置
在Starup ConfigureServices方法中配置模擬
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); // 啟用擴展庫 services.AddExtensions(Configuration); // 消息服務所使用的HttpClient名稱MESSAGESERVICE IHttpClientBuilder messageClient = services.AddHttpClient("MESSAGESERVICE", client => { // 設(shè)置基礎(chǔ)地址 client.BaseAddress = new Uri("http://api.hello.com/"); }); // 只有Mock配置設(shè)置為true時,才啟用,通過開發(fā)應用配置文件來配置 if (Configuration.GetValue<bool>("Mock")) { // 配置針對消息服務客戶端,POST到/message/send接口的請求,都將返回一個ResponseMessage messageClient.AddMockHttpMessageHandler() .AddMock<ResponseMessage>("/message/send", HttpMethod.Post, new ResponseMessage()); } }
注意,以上通過配置中的Mock屬性來決定是否開啟模擬功能,為了不影響正式發(fā)布,可以通過開發(fā)環(huán)境配置(appsettings.Development.json)來開啟模擬:
{ "Mock": true }
5.控制器
[Route("api/order")] [ApiController] public class OrderController : ControllerBase { readonly HttpClient messageClient; public OrderController(IHttpClientFactory clientFactory) { // 創(chuàng)建消息服務所使用的客戶端,名稱與配置所使用的名稱一致 // 實際項目中千萬不要寫上哦~ messageClient = clientFactory.CreateClient("MESSAGESERVICE"); } [HttpPost] public async Task<ResponseMessage> SaveOrder([FromBody]Order order) { // 保存訂單,省略了.... // 調(diào)用消息服務接口 ResponseMessage response = await messageClient.PostAsync<ResponseMessage>( "/message/send", new SendMessageRequest() { MessageId = Guid.NewGuid().ToString("N").ToLower(), Message = "訂單已提交", UserIds = new List<int>() { 1,2,3} }); // 根據(jù)消息服務返回應答繼續(xù)處理,省略了... return response; } }
6.啟動,然后通過Api測試工具(如Postman)向/api/order POST請求,接口將返回以下應答:
{ "code": "0", "message": null, "isSuccess": true }
如上,通過Http請求模擬,我們實現(xiàn)了訂單服務對消息服務的依賴。
二、在單元測試中使用
單元測試中,針對模擬應答的配置是一樣的,我們可以通過測試用例模擬各種不同的應答,包括異常,來對執(zhí)行路徑進行測試。
[Fact] public async Task Test1() { IServiceCollection services = new ServiceCollection() .AddExtensions(); services.AddHttpClient("TESTCLIENT") .AddMockHttpMessageHandler() // 請求/test/exception將觸發(fā)異常 .AddMock("/test/exception", HttpMethod.Get, new Exception("")) // 針對 /test/404 返回404應答 .AddMock("/test/404", HttpMethod.Get, HttpStatusCode.NotFound) // 返回指定類型 .AddMock<int>("/test/obj", HttpMethod.Get, 100) // 自定義條件及應答 .AddMock(request => { if (request.Headers.Contains("hello")) { return true; } return false; }, async (request, response) => { // 如果是調(diào)用第三方服務,你可以在這里檢查request發(fā)出的請求內(nèi)容是否正確 // 自定義應答內(nèi)容 await response.WriteObjectAsync(new { test = "Hello World" }); }) // 針對所有請求返回字符串Hello .AddMock("*", HttpMethod.Get, "Hello"); IServiceProvider provider = services.BuildServiceProvider(); IHttpClientFactory clientFactory = provider.GetRequiredService<IHttpClientFactory>(); HttpClient client = clientFactory.CreateClient("TESTCLIENT"); client.BaseAddress = new Uri("http://localhost"); HttpResponseMessage resposne = await client.GetAsync("/test/404"); Assert.Equal(HttpStatusCode.NotFound, resposne.StatusCode); }
三、示例
詳細示例請參考GitHub
Xfrogcn.AspNetCore.Extensions地址:GitHub Gitee
以上就是ASP.NET Core擴展庫之Http請求模擬功能的使用的詳細內(nèi)容,更多關(guān)于ASP.NET Core Http請求模擬功能的使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
.NET微信小程序用戶數(shù)據(jù)的簽名驗證和解密代碼
這篇文章主要介紹了.NET微信小程序用戶數(shù)據(jù)的簽名驗證和解密代碼,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12.Net?Core使用Coravel實現(xiàn)任務調(diào)度的完整步驟
最近在使用調(diào)度程序創(chuàng)建簡單的服務,該服務將執(zhí)行一些重復的IO操作,使用的是Coravel調(diào)度庫,下面這篇文章主要給大家介紹了關(guān)于.Net?Core使用Coravel實現(xiàn)任務調(diào)度的完整步驟,需要的朋友可以參考下2022-08-08DotNet OnPreRender(EventArgs e) 事件常用的方法
DotNet OnPreRender(EventArgs e) 事件常用的方法,需要的朋友可以參考下。2011-07-07