当前位置: 移动技术网 > IT编程>开发语言>.net > ASP.NET Core针对一个使用HttpClient对象的类编写单元测试详解

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

2019年03月20日  | 移动技术网IT编程  | 我要评论

宋之枭雄卢俊义,永作亜美,迦瓦尔

介绍

几年前,微软引入了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");
  }
}
  • 在以上测试中,我们期望获取一个成功的响应,并得到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 ()

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对移动技术网的支持。

原文地址:

作者: anthony giretti

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网