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中是使用路由中间件来匹配传 ...
随机推荐
- MyBatis从入门到精通(2):MyBatis XML方式的基本用法
本章将通过完成权限管理的常见业务来学习 MyBatis XML方式的基本用法 2.1一个简单的权限控制需求 权限管理的需求: 一个用户拥有若干角色,一个角色拥有若干权限,权限就是对某个模块资源的某种操 ...
- 列表 元组 range
2019 年 7 月 9 日 列表---list------容器 列表:存储数据,支持多个数据类型,比如 :字符串 数字 布尔值 列表 集合 元组 特点 : 有序 可变 支持索引 (定义一个列表不 ...
- 鸽巢原理及其扩展——Ramsey定理
第一部分:鸽巢原理 咕咕咕!!! 然鹅大家还是最熟悉我→ a数组:but 我也很重要 $:我好像也出现不少次 以上纯属灌水 文章简叙:鸽巢原理对初赛时的问题求解以及复赛的数论题目都有启发意义.直接的初 ...
- 比赛:小奔的矩形solution
分析: 交叉相乘,然后除以最大公因数(为了减少爆常数的可能性std做了两次,数据很大),得到的两个数相加减二就是答案 代码: var p,q,n,m,a,b,i:int64; begin readln ...
- DML语言DDL
DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令是用来对数据库里的数据进行操作的语言 . D ...
- [PTA] 数据结构与算法题目集 6-3 求链式表的表长
Length( List L ){ int res=0; while(L!=NULL){ res++; L=L->Next; } return res; }
- Makefile简单的配置
一.文件配置目录 1)原目录 demo ├── Makefile ├── demo.cpp ├── demo.hpp └── main.cpp 2)make之后的目录 demo ├── Makefil ...
- DEDE(织梦)后台发表文章无法编辑(出现空白)方法
- python课堂整理14---函数式编程
一.分类 当下主流的编程方法大体分为三类 1. 面向过程 2. 函数式 3. 面向对象 二.函数式编程:函数式 = 编程语言定义的函数 + 数学意义的函数 特征:1. 不可变数据 2. 第一类对象 3 ...
- vue使用video.js解决m3u8视频播放格式
今天被这个关于m3u8视频播放不了搞了一下午,这个项目所有的视频流都是m3u8格式的,后台给我们返回的都是m3u8格式的视频流,解决了好长时间,看了好多博客,只有这个博客给我点启发,去解决这个问题,请 ...