ASP.NET Core针对一个使用HttpClient对象的类编写单元测试详解
介绍
几年前,微软引入了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 (本地下载)
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
原文地址: how to unit test a class that consumes an httpclient with ihttpclientfactory in asp.net core?
作者: anthony giretti
上一篇: css3之resize