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中是使用路由中间件来匹配传 ...
随机推荐
- Spring源码阅读-ApplicationContext体系结构分析
目录 继承层次图概览 ConfigurableApplicationContext分析 AbstractApplicationContext GenericApplicationContext Gen ...
- 使用wincc C脚本查找窗口句柄的方法
关于窗口句柄的用法,网上可以搜到很多相关的文章,本文以windows API接口函数为例,简单介绍一下基本使用,主要包括找到此窗体,在找到的窗体写入数据,对窗体进行关闭,最大化,最小化的操作: 1.利 ...
- ~~在python中踩过的坑以及问题~~(不断更新)
python说简单也不难,但是在这其中大大小小的点 真的是有够折磨人欸! 1. input 输入的时候,即使输入的是数字,数据类型也是字符串 2. 字符串本质上来看可以看作有序数组 3 ...
- 【动态规划例题-数塔问题】-C++
描述 观察下面的数字金字塔.写一个程序查找从最高点到底部任意处结束的路径,使路径经过数字的和最大.每一步可以 从当前点走到左下方的点也可以到达右下方的点. 在上面的样例中,从13到8到26到15到24 ...
- 网络编程模型及TCP、UDP编程设计
1.Linux网络模型 Linux网络编程--->>>socket套接字的编程 2.TCP网络模型 ...
- NOIp2018普及组T3暨洛谷P5017 摆渡车:题解
题目链接:https://www.luogu.org/problemnew/show/P5017 emm,这次的真的不简单的,T3比T4难? 醉了... 蒟蒻肯定没有其他大佬讲的好啊,但肯定尽力,真的 ...
- 【CYH-02】noip2018数论模拟赛:赛后题解
1.小奔的矩阵 2.大奔的方案 3.小奔与不等四边形 4.小奔的方案 当然本次比赛肯定难度不会仅限于此啦!后续还会--
- 实现通过COM组件方式实现java调用C#写的DLL文件的完整demo
最近因为工作需要,客户那边工程师使用的是JAVA语言开发的程序,我们这边平台中是用C#语言开发的,因为有些操作必须统一,所以我在网上查找解决方法,自己也实践过,在这里做个笔记吧,分享一下. 声明:下面 ...
- 使用canvas来完成线性渐变和径向渐变的功能
fillStyle的第二种使用情况就是渐变色的填充.渐变色就分为线性渐变色和径向渐变色. 线性渐变:大致分为两步 这里又会使用到canvas的两个新的函数. 第一步 : 使用一个新的函数cre ...
- cesium 学习(四) Hello World
一.前言 之前的文章都是基础,搭建环境.部署Cesium.学习资料等等.现在简单入手,一个Hello World页面开发. 二.Hello World 感觉Hello World没有什么特别需要讲的, ...