介紹
幾年前,微軟引入了HttpClient類來替代HttpWebRequest來發送Web請求。這個新的類更易于使用,更加簡潔,更具有異步性,且易于擴展。
HttpClient類有一個可以接受HttpMessageHandler類對象的構造函數。HttpMessageHandler類對象可以接受一個請求(HttpRequestMessage), 并返回響應(HttpResponseMessage)。它的功能完全取決于它的實現。默認情況下HttpClient使用的是HttpClientHandler,HttpClientHandler是一個處理程序,它向網絡服務器發送請求并從服務器返回響應。在本篇博文中,我們將通過繼承DelegatingHandler來創建自己的HttpMessageHandler。
為了實現以上功能,HttpClient對象不可以直接使用,而是需要與允許使用IHttpClientFactory接口進行模擬的依賴注入一起使用。
讓我們來偽造一個HttpMessageHandler
下面的例子中,我們只討論HttpResponseMessage, 不會處理HttpRequestMessage。
以下是我偽造的一個HttpMessageHandler對象。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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); } } |
這里我添加了一個需要HttpResponseMessage構造函數,然后復寫了SendAsync方法, 在該方法中直接返回了構造函數中傳入的HttpResponseMessage對象。
編寫一個使用IHttpClientFactory接口的服務
下面我們需要編寫一個UserService類,這個類提供了一個GetUsers方法,來從遠程服務器端獲取用戶列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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請求返回的用戶類
1
2
3
4
5
|
public class User { public string FirstName { get ; set ; } public string LastName { get ; set ; } } |
如你所見,使用HttpClientFactory允許我們模擬HttpClient實例化
測試服務
在下面的單元測試中,我們會使用XUnit、FluentAssertion、NSubstitute
測試場景1: 模擬一個請求,返回2個用戶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
|
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" ); } } |
- 在以上測試中,我們期望獲取一個成功的響應,并得到2個用戶的信息。
- 我們期望從Service中得到的數據是JSON格式的。
- 我們使用一個偽造的處理程序初始化了一個HttpClient對象,然后定義了我們期望的得到的偽造對象httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);
測試場景2: 模擬一個404錯誤,返回空數據
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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(); } } |
和測試場景1類似,當一個Http請求返回Not Found, 它的結果集是Null
總結
本篇作者講解了在ASP.NET Core中如何偽造HttpClient來測試持有HttpClient對象的類。這里主要是通過偽造的DelegatingHandler對象來創建一個HttpClient對象,并使用IHttpClientFactory來獲取偽造的HttpClient來達到目的。
本篇源代碼:https://github.com/lamondlu/Sample_TestHttpClient
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core?
作者: Anthony Giretti
原文鏈接:https://www.cnblogs.com/lwqlun/p/10215929.html