ASP.NET Core針對(duì)一個(gè)使用HttpClient對(duì)象的類編寫單元測(cè)試詳解
介紹
幾年前,微軟引入了HttpClient類來替代HttpWebRequest來發(fā)送Web請(qǐng)求。這個(gè)新的類更易于使用,更加簡(jiǎn)潔,更具有異步性,且易于擴(kuò)展。
HttpClient類有一個(gè)可以接受HttpMessageHandler類對(duì)象的構(gòu)造函數(shù)。HttpMessageHandler類對(duì)象可以接受一個(gè)請(qǐng)求(HttpRequestMessage), 并返回響應(yīng)(HttpResponseMessage)。它的功能完全取決于它的實(shí)現(xiàn)。默認(rèn)情況下HttpClient使用的是HttpClientHandler,HttpClientHandler是一個(gè)處理程序,它向網(wǎng)絡(luò)服務(wù)器發(fā)送請(qǐng)求并從服務(wù)器返回響應(yīng)。在本篇博文中,我們將通過繼承DelegatingHandler來創(chuàng)建自己的HttpMessageHandler。
為了實(shí)現(xiàn)以上功能,HttpClient對(duì)象不可以直接使用,而是需要與允許使用IHttpClientFactory接口進(jìn)行模擬的依賴注入一起使用。
讓我們來偽造一個(gè)HttpMessageHandler
下面的例子中,我們只討論HttpResponseMessage, 不會(huì)處理HttpRequestMessage。
以下是我偽造的一個(gè)HttpMessageHandler對(duì)象。
public class FakeHttpMessageHandler : DelegatingHandler
{
private HttpResponseMessage _fakeResponse;
public FakeHttpMessageHandler(HttpResponseMessage responseMessage)
{
_fakeResponse = responseMessage;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await Task.FromResult(_fakeResponse);
}
}
這里我添加了一個(gè)需要HttpResponseMessage構(gòu)造函數(shù),然后復(fù)寫了SendAsync方法, 在該方法中直接返回了構(gòu)造函數(shù)中傳入的HttpResponseMessage對(duì)象。
編寫一個(gè)使用IHttpClientFactory接口的服務(wù)
下面我們需要編寫一個(gè)UserService類,這個(gè)類提供了一個(gè)GetUsers方法,來從遠(yuǎn)程服務(wù)器端獲取用戶列表。
public class UserService
{
private readonly IHttpClientFactory _httpFactory;
public UserService(IHttpClientFactory httpFactory)
{
_httpFactory = httpFactory;
}
public async Task<List<User>> GetUsers(string url)
{
using (HttpClient httpclient = _httpFactory.CreateClient())
{
using (HttpResponseMessage response = await httpclient.GetAsync(url))
{
if (response.StatusCode == HttpStatusCode.OK)
{
List<User> users = await response.Content.ReadAsAsync<List<User>>();
return users;
}
return null;
}
}
}
}
以下是Api請(qǐng)求返回的用戶類
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
如你所見,使用HttpClientFactory允許我們模擬HttpClient實(shí)例化
測(cè)試服務(wù)
在下面的單元測(cè)試中,我們會(huì)使用XUnit、FluentAssertion、NSubstitute
測(cè)試場(chǎng)景1: 模擬一個(gè)請(qǐng)求,返回2個(gè)用戶
public class UserServiceTests
{
[Fact]
public async Task WhenACorrectUrlIsProvided_ServiceShouldReturnAlistOfUsers()
{
// Arrange
var users = new List<User>
{
new User
{
FirstName = "John",
LastName = "Doe"
},
new User
{
FirstName = "John",
LastName = "Deere"
}
};
var httpClientFactoryMock = Substitute.For<IHttpClientFactory>();
var url = "http://good.uri";
var fakeHttpMessageHandler = new FakeHttpMessageHandler(new HttpResponseMessage() {
StatusCode = HttpStatusCode.OK,
Content = new StringContent(JsonConvert.SerializeObject(users), Encoding.UTF8, "application/json")
});
var fakeHttpClient = new HttpClient(fakeHttpMessageHandler);
httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);
// Act
var service = new UserService(httpClientFactoryMock);
var result = await service.GetUsers(url);
// Assert
result
.Should()
.BeOfType<List<User>>()
.And
.HaveCount(2)
.And
.Contain(x => x.FirstName == "John")
.And
.Contain(x => x.LastName == "Deere")
.And
.Contain(x => x.LastName == "Doe");
}
}
- 在以上測(cè)試中,我們期望獲取一個(gè)成功的響應(yīng),并得到2個(gè)用戶的信息。
- 我們期望從Service中得到的數(shù)據(jù)是JSON格式的。
- 我們使用一個(gè)偽造的處理程序初始化了一個(gè)HttpClient對(duì)象,然后定義了我們期望的得到的偽造對(duì)象httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);
測(cè)試場(chǎng)景2: 模擬一個(gè)404錯(cuò)誤,返回空數(shù)據(jù)
public class UserServiceTests
{
[Fact]
public async Task WhenABadUrlIsProvided_ServiceShouldReturnNull()
{
// Arrange
var httpClientFactoryMock = Substitute.For<IHttpClientFactory>();
var url = "http://bad.uri";
var fakeHttpMessageHandler = new FakeHttpMessageHandler(new HttpResponseMessage() {
StatusCode = HttpStatusCode.NotFound
});
var fakeHttpClient = new HttpClient(fakeHttpMessageHandler);
httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);
// Act
var service = new UserService(httpClientFactoryMock);
var result = await service.GetUsers(url);
// Assert
result
.Should()
.BeNullOrEmpty();
}
}
和測(cè)試場(chǎng)景1類似,當(dāng)一個(gè)Http請(qǐng)求返回Not Found, 它的結(jié)果集是Null
總結(jié)
本篇作者講解了在ASP.NET Core中如何偽造HttpClient來測(cè)試持有HttpClient對(duì)象的類。這里主要是通過偽造的DelegatingHandler對(duì)象來創(chuàng)建一個(gè)HttpClient對(duì)象,并使用IHttpClientFactory來獲取偽造的HttpClient來達(dá)到目的。
本篇源代碼:https://github.com/lamondlu/Sample_TestHttpClient (本地下載)
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core?
作者: Anthony Giretti
相關(guān)文章
asp.net利用反射實(shí)現(xiàn)給model類賦值的方法
這篇文章主要介紹了asp.net利用反射實(shí)現(xiàn)給model類賦值的方法,結(jié)合實(shí)例形式分析了asp.net使用反射給model類賦值的操作步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-03-03
Asp.net Core Jenkins Docker實(shí)現(xiàn)一鍵化部署的實(shí)現(xiàn)
這篇文章主要介紹了Asp.net Core Jenkins Docker實(shí)現(xiàn)一鍵化部署的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01
.NET使用DinkToPdf將HTML轉(zhuǎn)成PDF的示例代碼
這篇文章主要介紹了.NET使用DinkToPdf將HTML轉(zhuǎn)成PDF的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
VS2019中.NET如何實(shí)現(xiàn)打日志功能
本文主要介紹了VS2019中.NET如何實(shí)現(xiàn)打日志功能,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03
asp.net截屏功能實(shí)現(xiàn)截取web頁面
這篇文章主要介紹了asp.net截屏功能實(shí)現(xiàn)截取web頁面,是非常實(shí)用的一個(gè)功能,需要的朋友可以參考下2014-08-08
詳解Asp.net web.config customErrors 如何設(shè)置
這篇文章主要介紹了詳解Asp.net web.config customErrors 如何設(shè)置,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-02-02
Gridview使用CheckBox全選與單選采用js實(shí)現(xiàn)同時(shí)高亮顯示選擇行
Gridview使用CheckBox單選與全選功能再次進(jìn)行簡(jiǎn)單演示,選中的行,使用高亮顯示,讓用戶一目了然看到哪一行被選擇了,在項(xiàng)目中很實(shí)用的,開發(fā)中的朋友們可要考慮一下哦2013-01-01

