ASP.NET CORE 2.* 利用集成测试框架覆盖HttpClient相关代码
我的asp.net core 项目里面大部分功能都是去调用别人的API ,大量使用HttpClient,公司单元测试覆盖率要求95%以上,很难做到不mock HttpClient 达到这个指数。
以下方法是我自己总结的在单元测试里 mock httpClient 的方式,基本思路是利用集成测试框架,mock外部调用的API ,达到httpClient 代码的覆盖。
代码地址:https://github.com/Halo-Shaka/LearningAspNetCoreIntegrationTesting.git
举个例子,创建一个简单的asp.net core 项目,里面只有一个api , api/values, 是个get 方法,
get 方法内部是去调用外部API, 随便写个方法 向google 发一个信息。
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly IOptions<AppSettings> _options;
public ValuesController(IHttpClientFactory httpClientFactory, IOptions<AppSettings> options)
{
_httpClientFactory = httpClientFactory;
_options = options;
}
// GET api/values
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient();
var url = _options.Value.Url;
var payload = new
{
From = "China"
};
var requestMessage = new HttpRequestMessage(HttpMethod.Post, url)
{
Content = new StringContent(JsonConvert.SerializeObject(payload), Encoding.UTF8, "application/json")
};
try
{
var response = await client.SendAsync(requestMessage);
var content = await response.Content.ReadAsStringAsync();
if (response.StatusCode == HttpStatusCode.OK)
{
return Ok(content);
}
return BadRequest();
}
catch (Exception e)
{
return StatusCode(502);
}
}
}
这里面有个需要注意的地方,使用注入的httpClient, 外部访问的地址需要是配置的
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddHttpClient();
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
} app.UseHttpsRedirection();
app.UseMvc();
}
}

到此为止,基本功能就写完了,现在来写测试代码
添加 XUnit单元测试项目,添加如下包
Microsoft.AspNetCore.App
Microsoft.AspNetCore.Mvc.Testing
Microsoft.NET.Test.Sdk
Moq
利用集成测试的虚拟站点,把我们需要调用的外部API 伪造出来,
[Route("gateway")]
public class MockGatewayController : ControllerBase
{
[HttpPost]
public ActionResult<string> Logon([FromBody]LogonRequest request)
{
if (request.From == "China")
{
var behavior = MockGatewayData.MockBehavior;
return behavior.LogonResult();
}
return string.Empty;
}
}
public class LogonRequest
{
public string From { get; set; }
}
public interface IGatewayMockBehavior
{
ActionResult<string> LogonResult();
}
public class MockGatewayData
{
public static IGatewayMockBehavior MockBehavior { get; set; }
}
MockGatewayData类的作用是 让客户端能够访问到服务端,并指定想要返回的结果
接着创建 GenericWebApplicationFactory,并把刚伪造的 controller 指定到虚拟站点里面,
public class GenericWebApplicationFactory : WebApplicationFactory<Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
services.AddMvc().AddApplicationPart(typeof(MockGatewayController).Assembly).AddControllersAsServices();
});
}
}
最后写测试代码
public class ValuesControllerTest : IClassFixture<GenericWebApplicationFactory>
{
public ValuesControllerTest(GenericWebApplicationFactory factory, ITestOutputHelper output)
{
this.factory = factory;
this.output = output;
} protected GenericWebApplicationFactory factory;
protected ITestOutputHelper output; [Fact]
public void GetRequest_GatewayInaccessible_ShouldReturn502()
{
var client = factory.WithWebHostBuilder(p => p.ConfigureServices(services =>
{
services.PostConfigure<AppSettings>(options => { options.Url = "https://aaaaaaaa"; });
})).CreateClient();
var response = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "api/values")).Result;
Assert.Equal(HttpStatusCode.BadGateway, response.StatusCode);
} [Fact]
public void GetRequest_GatewayOnFailed_ShouldReturn400()
{
var behavior = new Mock<IGatewayMockBehavior>();
behavior.Setup(p => p.LogonResult()).Returns(new BadRequestResult());
MockGatewayData.MockBehavior = behavior.Object; var client = CreateHttpClient();
var response = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "api/values")).Result;
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
} [Fact]
public void GetRequest_GatewayOnSuccess_ShouldReturn200()
{
var behavior = new Mock<IGatewayMockBehavior>();
behavior.Setup(p => p.LogonResult()).Returns(new ActionResult<string>("success"));
MockGatewayData.MockBehavior = behavior.Object; var client = CreateHttpClient();
var response = client.SendAsync(new HttpRequestMessage(HttpMethod.Get, "api/values")).Result;
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
} private HttpClient CreateHttpClient()
{
var client = factory.WithWebHostBuilder(p => p.ConfigureServices(services =>
{
services.PostConfigure<AppSettings>(options => { options.Url = "http://localhost/gateway"; }); services.AddSingleton(typeof(IHttpClientFactory), new MockHttpClientFactory
{
InjectHttpClient = factory.CreateClient
});
})).CreateClient(); return client;
}
}
最后看下覆盖率,整个controller 里面httpClient 全都被覆盖了

代码地址:
https://github.com/Halo-Shaka/LearningAspNetCoreIntegrationTesting.git
ASP.NET CORE 2.* 利用集成测试框架覆盖HttpClient相关代码的更多相关文章
- ASP.NET Core的身份认证框架IdentityServer4--入门
ASP.NET Core的身份认证框架IdentityServer4--入门 2018年08月11日 10:09:00 qq_42606051 阅读数 4002 https://blog.csdn ...
- Blazor——Asp.net core的新前端框架
原文:Blazor--Asp.net core的新前端框架 Blazor是微软在Asp.net core 3.0中推出的一个前端MVVM模型,它可以利用Razor页面引擎和C#作为脚本语言来构建WEB ...
- 基于Asp.Net Core,利用ZXing来生成二维码的一般流程
本文主要介绍如何在.net环境下,基于Asp.Net Core,利用ZXing来生成二维码的一般操作.对二维码工作原理了解,详情见:https://blog.csdn.net/weixin_36191 ...
- ASP.NET Core开发-使用Nancy框架
Nancy简介 Nancy是一个轻量级的独立的框架,下面是官网的一些介绍: Nancy 是一个轻量级用于构建基于 HTTP 的 Web 服务,基于 .NET 和 Mono 平台,框架的目标是保持尽可能 ...
- 使用Angular 4、Bootstrap 4、TypeScript和ASP.NET Core开发的Apworks框架案例应用:Task List
最近我为我自己的应用开发框架Apworks设计了一套案例应用程序,并以Apache 2.0开源,开源地址是:https://github.com/daxnet/apworks-examples,目的是 ...
- ASP.NET Core Web API 集成测试中使用 Bearer Token
在 ASP.NET Core Web API 集成测试一文中, 我介绍了ASP.NET Core Web API的集成测试. 在那里我使用了测试专用的Startup类, 里面的配置和开发时有一些区别, ...
- asp.net core 集成 log4net 日志框架
asp.net core 集成 log4net 日志框架 Intro 在 asp.net core 中有些日志我们可能想输出到数据库或文件或elasticsearch等,如果不自己去实现一个 Logg ...
- asp.net core 系列 8 Razor框架路由(下)
三.页面路由操作约定 接着上篇讲asp.net core 系列 7 Razor框架路由.在上篇继续第三节 "页面路由操作约定" 的最后一小节 AddPageRoute . 3.3. ...
- asp.net core 系列 5 MVC框架路由(上)
一. 概述 介绍asp.net core路由时,我初步想了下,分几篇来说明. 路由的知识点很多,参考了官方文档提取出一些重要的知识点来说. 在ASP.NET Core中是使用路由中间件来匹配传 ...
随机推荐
- 谷歌地球 Google Earth v7.3.2.5495 专业版
谷歌地球(Google Earth,GE)是一款谷歌公司开发的虚拟地球软件,它把卫星照片.航空照相和GIS布置在一个地球的三维模型上.谷歌地球于2005年向全球推出,被<PC 世界杂志>评 ...
- vue+element项目中使用el-dialog弹出Tree控件报错问题
1. 按正常的点击按钮,显示dialog弹出的Tree控件,然后把该条数据下的已经选中的checkbox , 用setCheckedNodes或者setCheckedKeys方法选择上 , 报下面这个 ...
- Guid几种格式及之间的互换,以及利用Base64缩短guid的长度到22个字符和还原
1.Guid.NewGuid().ToString("N") 结果为: 38bddf48f43c48588e0d78761eaa1ce6 2.Guid.NewGuid().ToSt ...
- css基础5
今天在这里跟大家分享css基础最核心的部分,浮动和定位.话不多说,直接上干货! 一.浮动 定义:定位元素是相对于其正常位置应该出现的位置.定位元素的位置是相对于自身.父级元素位置.其他元素以及浏览器窗 ...
- c++小游戏——五子棋
#include<iostream> #include<iomanip> #include<cstring> using namespace std; const ...
- Shiro在Web环境下集成Spring的大致工作流程
1,Shiro提供了对Web环境的支持,其通过一个 ShiroFilter 入口来拦截需要安全控制的URL,然后进行相应的控制. ①配置的 ShiroFilter 实现类为:org.spri ...
- Polya定理与Burnside引理
也许更好的阅读体验 \(Burnside引理\) 公式 \(\begin{aligned}L=\frac{1}{|G|}\sum_{i=1}^{|G|}D_{G_i}\end{aligned}\) 一 ...
- Kafka配置信息
Kafka配置信息 broker配置信息 属性 默认值 描述 broker.id 必填参数,broker的唯一标识 log.dirs /tmp/kafka-logs Kafka数据存放的目录.可以指定 ...
- c语言进阶13-线性表之顺序表
一. ACM算法:顺序表的查找 顺序表的查找指获取顺序表的第i个元素.对于线性表的顺序存储结构来说,如果我们要实现获取元素的操作(GetElem),即将线性表L中的第i个位置元素值返回.就程序而言,只 ...
- es6的基本用法
1. let和const <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...