内容字号:默认大号超大号

段落设置:段首缩进取消段首缩进

字体设置:切换到微软雅黑切换到宋体

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

2019-01-04 19:39 出处:清屏网 人气: 评论(0

介绍

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

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

测试服务

在下面的单元测试中,我们会使用 XUnitFluentAssertionNSubstitute

测试场景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");
    }
}
  • 在以上测试中,我们期望获取一个成功的响应,并得到2个用户的信息。
  • 我们期望从Service中得到的数据是JSON格式的。
  • 我们使用一个伪造的处理程序初始化了一个 HttpClient 对象,然后定义了我们期望的得到的伪造对象 httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

测试场景2: 模拟一个404错误,返回空数据

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

分享给小伙伴们:
本文标签: ASP.NETCoreHttpClient

相关文章

发表评论愿您的每句评论,都能给大家的生活添色彩,带来共鸣,带来思索,带来快乐。

CopyRight © 2015-2016 QingPingShan.com , All Rights Reserved.

清屏网 版权所有 豫ICP备15026204号