asp.netcore中如何针对一个使用httpclient对象的类编写单元测试(代码片段)

author author     2022-12-23     166

关键词:

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

原文地址: How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core?
作者: Anthony Giretti
译者: Lamond Lu

技术图片

介绍#

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

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

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

让我们来伪造一个HttpMessageHandler#

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

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

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

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

Copy
public class User public string FirstName get; set; public string LastName get; set;

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

测试服务#

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

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

Copy
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错误,返回空数据#

Copy
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.netcore中如何针对一个使用httpclient对象的类编写单元测试(代码片段)

...:HowtounittestaclassthatconsumesanHttpClientwithIHttpClientFactoryinASP.NETCore?作者:AnthonyGiretti译者:LamondLu介绍几年前,微软引入了HttpClient类来替代HttpWebRequest来发送Web请求。这个新的类更易于使用,更加简洁,更具有异步性,且易于扩展。H... 查看详情

我们如何在 ASP.Net Core 中使用 HttpClient?

】我们如何在ASP.NetCore中使用HttpClient?【英文标题】:HowcanweuseHttpClientinASP.NetCore?【发布时间】:2019-09-1422:32:01【问题描述】:我正在编写ASP.NetMVCCore2.2Web应用程序。我需要使用HTTP或HTTPS从另一个Web服务器获取数据。我该怎么做... 查看详情

如何在 ASP.NET Core 中保持对象活动?

】如何在ASP.NETCore中保持对象活动?【英文标题】:HowtokeepobjectaliveinASP.NETCore?【发布时间】:2018-09-0515:40:06【问题描述】:我有一个使用C++库(SWIG)的.NETCoreMVC应用程序(C#)。在C#中,我需要创建其中一个类的实例,预设其回调并在... 查看详情

在asp.netcore中上传文件

简介ASP.NETCore支持使用缓冲的模型绑定(针对较小文件)和无缓冲的流式传输(针对较大文件)上传一个或多个文件。传文件的作用1.上传是支持上传任何文件的,图片只是上传的一种。2.根据扩展名进行区分... 查看详情

在asp.netcore中上传文件(代码片段)

...地文件或网络文件)从客户端上传至服务器存储。ASP.NETCore支持使用缓冲的模型绑定(针对较小文件)和无缓冲的流式传输(针对较大文件)上传一个或多个文件。缓冲和流式传输是上传文件的两种常见方法。... 查看详情

asp.netcore中middleware的使用(代码片段)

 ASP.NET5中Middleware的基本用法在ASP.NET5里面引入了OWIN的概念,大致意思是将网站部署、服务器、中间组件以及应用分离开,这里提到的Middleware就是中间组件。这里引用asp.net网站的介绍图Middleware的作用有点类似于httpmodule,服... 查看详情

如何在 ASP.NET Core 中使用区域

】如何在ASP.NETCore中使用区域【英文标题】:HowtouseanAreainASP.NETCore【发布时间】:2016-07-3120:05:14【问题描述】:如何在ASP.NETCore中使用Area?我有一个需要管理部分的应用。此部分要求将其视图放置在该区域中。所有以Admin/开头的... 查看详情

asp.netcore6框架揭秘实例演示[16]:内存缓存与分布式缓存的使用(代码片段)

.NET提供了两个独立的缓存框架,一个是针对本地内存的缓存,另一个是针对分布式存储的缓存。前者可以在不经过序列化的情况下直接将对象存储在应用程序进程的内存中,后者则需要将对象序列化成字节数组并存储到一个独... 查看详情

如何在 ASP.NET Core 中使用 jQuery 库?

】如何在ASP.NETCore中使用jQuery库?【英文标题】:HowdoIuseajQuerylibaryinASP.NETCore?【发布时间】:2019-07-2601:13:51【问题描述】:我正在使用ASP.NETCore2.2开发一个网站,主要使用剃须刀页面。我正在尝试制作一个树表,并找到了一个非... 查看详情

如何在 ASP.NET Core 中使用 npm

】如何在ASP.NETCore中使用npm【英文标题】:HowtousenpmwithASP.NETCore【发布时间】:2016-10-2211:26:20【问题描述】:我正在使用npm来管理我的ASP.NETCore应用程序所需的jQuery、Bootstrap、FontAwesome和类似的客户端库。对我有用的方法首先是在... 查看详情

asp.netcore中托管spa应用

...景,我们需要一个前后端分离的应用,服务端API使用ASP.NETCore开发,前端有两套,一个是用于所有用户的客户端,另一个是给管理员使用的管理后台,使用asp.netcore的hosting作为后端+前端的web服务器。应为默认情况下没有开启hostin... 查看详情

如何在 asp.net core 2.1 中使用 net.tcp 服务

】如何在asp.netcore2.1中使用net.tcp服务【英文标题】:HowdoIconsumeanet.tcpserviceinasp.netcore2.1【发布时间】:2019-04-0212:26:44【问题描述】:我正在构建一个asp.netcore2.1Web应用程序,我需要调用一个旧的net.tcp端点来获取有关预订的详细信... 查看详情

如何在 ASP.​NET Core 中使用 jquery

】如何在ASP.​NETCore中使用jquery【英文标题】:HowtousejqueryinASP.​NETCore【发布时间】:2016-10-2118:54:18【问题描述】:我创建了一个ASP.NET核心模板并编写了一个jquery脚本。当我查看页面时,我看到jquery已加载到页面中,但脚本没有... 查看详情

asp.netcore1.x/asp.netcore2.0中如何加载多个配置文件

写这篇文章,来简单的谈一下,asp.netcore中,如何加载多配置文件,如有错误请斧正。在1.x的时候,我们是自己配置WebHostBuilder而在2.0的时候,efcore团队,将配置写到了一个CreateDefaultBuilder,这是一个预配置,人家为了方便做的。... 查看详情

asp.netcore中如何使用缓存(代码片段)

相关知识预备序列化序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式(json/xml等)的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区,以后就可以通过从存储区中读取或反序列化对象的状... 查看详情

如何使用 ASP.NET Core 进行流式传输

】如何使用ASP.NETCore进行流式传输【英文标题】:HowtostreamwithASP.NETCore【发布时间】:2017-03-1318:58:44【问题描述】:如何在ASP.NETCore中正确地流式传输响应?有一个这样的控制器(UPDATEDCODE):[HttpGet("test")]publicasyncTaskGetTest()HttpCont... 查看详情

如何获取 ASP.NET Core 中所有路由的列表?

】如何获取ASP.NETCore中所有路由的列表?【英文标题】:HowtogetalistofallroutesinASP.NETCore?【发布时间】:2015-04-1017:24:11【问题描述】:在ASP.NETCore中,有没有办法查看Startup中定义的所有路由的列表?我们使用IRouteBuilder的MapRoute扩展... 查看详情

如何在 ASP.NET Core 中基于 appsettings 有条件地使用授权

】如何在ASP.NETCore中基于appsettings有条件地使用授权【英文标题】:HowtoconditionallyuseAuthorizationbasedonappsettingsinASP.NETCore【发布时间】:2021-09-1912:14:20【问题描述】:我有一个ASP.NETCore3.1WebApi,我在其中使用基于OAuth的身份验证和授... 查看详情