首页 > 编程 > .NET > 正文

ASP.NET Core针对一个使用HttpClient对象的类编写单元测试详解

2024-07-10 12:48:34
字体:
来源:转载
供稿:网友

介绍

几年前,微软引入了HttpClient类来替代HttpWebRequest来发送Web请求。这个新的类更易于使用,更加简洁,更具有异步性,且易于扩展。

HttpClient类有一个可以接受HttpMessageHandler类对象的构造函数。HttpMessageHandler类对象可以接受一个请求(HttpRequestMessage), 并返回响应(HttpResponseMessage)。它的功能完全取决于它的实现。默认情况下HttpClient使用的是HttpClientHandler,HttpClientHandler是一个处理程序,它向网络服务器发送请求并从服务器返回响应。在本篇博文中,我们将通过继承DelegatingHandler来创建自己的HttpMessageHandler。

为了实现以上功能,HttpClient对象不可以直接使用,而是需要与允许使用IHttpClientFactory接口进行模拟的依赖注入一起使用。

让我们来伪造一个HttpMessageHandler

下面的例子中,我们只讨论HttpResponseMessage, 不会处理HttpRequestMessage。

以下是我伪造的一个HttpMessageHandler对象。

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方法,来从远程服务器端获取用户列表。

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请求返回的用户类

public class User{ public string FirstName { get; set; } public string LastName { get; set; }}

如你所见,使用HttpClientFactory允许我们模拟HttpClient实例化

测试服务

在下面的单元测试中,我们会使用XUnit、FluentAssertion、NSubstitute

测试场景1: 模拟一个请求,返回2个用户

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");  }}            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表