使用Microsoft.AspNetCore.TestHost进行完整的功能测试
简介
Microsoft.AspNetCore.TestHost是可以用于Asp.net Core 的功能测试工具。很多时候我们一个接口写好了,单元测试什么的也都ok了,需要完整调试一下,检查下单元测试未覆盖到的代码是否有bug。步骤为如下:程序打个断点->F5运行->通常需要登录个测试账号->查找要调试api的入口->获得断点开始调试=>代码报错?很多时候需要停止调试修改->回到第一步。如此反复循环,做着重复的工作,Microsoft.AspNetCore.TestHost正是为了解决这个问题,它可以让你使用xTest或者MSTest进行覆盖整个HTTP请求生命周期的功能测试。
进行一个简单的功能测试
新建一个Asp.net Core WebApi和xUnit项目
ValuesController里面自带一个Action
我们在xUnit项目里面模拟访问这个接口,首选安装如下nuget包:
Microsoft.AspNetCore.TestHost
Microsoft.AspNetCore.All(很多依赖懒得找的话直接安装这个集成包,百分之90涉及到AspNetCore的依赖都包含在里面)
然后需要引用被测试的AspnetCoreFunctionalTestDemo项目,新建一个测试类ValuesControllerTest
将GetValuesTest方法替换为如下代码,其中startup类是应用自AspnetCoreFunctionalTestDemo项目
[Fact] public void GetValuesTest(){ var client = new TestServer(WebHost.CreateDefaultBuilder().UseStartup<Startup>()).CreateClient(); string result = client.GetStringAsync("api/values").Result;Assert.Equal(result, JsonConvert.SerializeObject(new string[] { "value1", "value2" }));}
此时在ValueController打下断点
运行GetValuesTest调试测试
成功进入断点,我们不用启动浏览器,就可以进行完整的接口功能测试了。
修改内容目录与自动授权
上面演示了如何进行一个简单的功能测试,但是存在两个缺陷:
webApi在测试的时候实际的运行目录是在FunctionalTest目录下
对需要授权的接口不能正常测试,会得到未授权的返回结果
1.内容目录
我们可以在Controller的Get方法输出当前的内容目录
内容目录是在测试x项目下这与我们的预期不符,如果webapi项目对根目录下的文件有依赖关系例如appsetting.json则会找不到该文件,解决的办法是在webHost中手动指定运行根目录
[Fact]public void GetValuesTest() { var client = new TestServer(WebHost.CreateDefaultBuilder() .UseContentRoot(GetProjectPath("AspnetCoreFunctionalTestDemo.sln", "", typeof(Startup).Assembly)).UseStartup<Startup>()).CreateClient(); string result = client.GetStringAsync("api/values").Result;Assert.Equal(result, JsonConvert.SerializeObject(new string[] { "value1", "value2" })); }/// <summary>/// 获取工程路径/// </summary>/// <param name="slnName">解决方案文件名,例test.sln</param>/// <param name="solutionRelativePath">如果项目与解决方案文件不在一个目录,例如src文件夹中,则传src</param>/// <param name="startupAssembly">程序集</param>/// <returns></returns> private static string GetProjectPath(string slnName, string solutionRelativePath, Assembly startupAssembly) { string projectName = startupAssembly.GetName().Name; string applicationBasePath = PlatformServices.Default.Application.ApplicationBasePath; var directoryInfo = new DirectoryInfo(applicationBasePath); do{ var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, slnName)); if (solutionFileInfo.Exists){ return Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath, projectName));}directoryInfo = directoryInfo.Parent;} while (directoryInfo.Parent != null); throw new Exception($"Solution root could not be located using application root {applicationBasePath}.");}
GetProjectPath方法采用递归的方式找到startup的项目所在路径,此时我们再运行
2.自动授权
每次测试时手动登录这是一件很烦人的事情,所以我们希望可以自动话,这里演示的时cookie方式的自动授权
首先在startup文件配置cookie认证
namespace AspnetCoreFunctionalTestDemo { 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(); services.AddAuthentication(o => o.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(o =>{o.ExpireTimeSpan = new TimeSpan(0, 0, 30);o.Events.OnRedirectToLogin = (context) =>{context.Response.StatusCode = 401; return Task.CompletedTask;};}); } // 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();} app.UseAuthentication();app.UseMvc();}} }
这里覆盖了cookie认证失败的默认操作改为返回401状态码。
在valuesController新增登录的Action并配置Get的Action需要授权访问
namespace AspnetCoreFunctionalTestDemo.Controllers {[Route("api/[controller]")] public class ValuesController : Controller{ // GET api/values [HttpGet,Authorize] public IEnumerable<string> Get([FromServices]IHostingEnvironment env){ return new string[] { "value1", "value2" };} // POST api/values[HttpGet("Login")] public void Login(){ var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);identity.AddClaim(new Claim(ClaimTypes.Name, "huanent")); var principal = new ClaimsPrincipal(identity);HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal).Wait();}} }
此时我们使用测试项目测试Get方法
如我们预期,返回了401,说明未授权。我们修改下GetValuesTest
namespace FunctionalTest { public class ValuesControllerTest{[Fact] public void GetValuesTest(){ var client = new TestServer(WebHost.CreateDefaultBuilder().UseStartup<Startup>().UseContentRoot(GetProjectPath("AspnetCoreFunctionalTestDemo.sln", "", typeof(Startup).Assembly))).CreateClient(); var respone = client.GetAsync("api/values/login").Result;SetCookie(client, respone); var result = client.GetAsync("api/values").Result;} private static void SetCookie(HttpClient client, HttpResponseMessage respone){ string cookieString = respone.Headers.GetValues("Set-Cookie").First(); string cookieBody = cookieString.Split(';').First();client.DefaultRequestHeaders.Add("Cookie", cookieBody);} /// <summary>/// 获取工程路径 /// </summary>/// <param name="slnName">解决方案文件名,例test.sln</param>/// <param name="solutionRelativePath">如果项目与解决方案文件不在一个目录,例如src文件夹中,则传src</param>/// <param name="startupAssembly">程序集</param>/// <returns></returns>private static string GetProjectPath(string slnName, string solutionRelativePath, Assembly startupAssembly){ string projectName = startupAssembly.GetName().Name; string applicationBasePath = PlatformServices.Default.Application.ApplicationBasePath; var directoryInfo = new DirectoryInfo(applicationBasePath); do{ var solutionFileInfo = new FileInfo(Path.Combine(directoryInfo.FullName, slnName)); if (solutionFileInfo.Exists){ return Path.GetFullPath(Path.Combine(directoryInfo.FullName, solutionRelativePath, projectName));}directoryInfo = directoryInfo.Parent;} while (directoryInfo.Parent != null); throw new Exception($"Solution root could not be located using application root {applicationBasePath}.");}} }
我们首先访问api/Values/Login,获取到Cookie,然后讲cookie附在httpclient的默认http头上,这样就能够成功访问需要授权的接口了
总结
通过上面演示,我们已经可以很大程度地模拟了整个api请求,让我们可以方便地一键调试目标接口,再也不用开浏览器或postman了。
附上演示项目地址:https://github.com/huanent/AspnetCoreFunctionalTestDemo
原文:http://www.cnblogs.com/huanent/p/7886282.html
.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com
使用Microsoft.AspNetCore.TestHost进行完整的功能测试相关推荐
- ASP.NET Core 源码阅读笔记(5) ---Microsoft.AspNetCore.Routing路由
这篇随笔讲讲路由功能,主要内容在项目Microsoft.AspNetCore.Routing中,可以在GitHub上找到,Routing项目地址. 路由功能是大家都很熟悉的功能,使用起来也十分简单,从 ...
- CS0579 Duplicate 'Microsoft.AspNetCore.Mvc.ApplicationParts.ProvideApplicationPartFactoryAttribute
是由于系统中存在 两个不同版本的 Microsoft.AspNetCore.Mvc
- 剖析 Microsoft.AspNetCore.Identity 的精髓 ——菜鸟入门
学习目录 前言 初级 菜鸟入门 配置详解 简单二次开发 进阶 UserManager 解析 RoleManager 解析 Validator 解析 SignInManager 解析 关于如何使用 博客 ...
- Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException: Request body too large
.ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseUrls("http://localhost:6660");web ...
- 如何测试ASP.NET Core Web API
在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...
- 《ASP.NET Core 微服务实战》-- 读书笔记(第3章)
第 3 章 使用 ASP.NET Core 开发微服务 微服务定义 微服务是一个支持特定业务场景的独立部署单元.它借助语义化版本管理.定义良好的 API 与其他后端服务交互.它的天然特点就是严格遵守单 ...
- 如何测试 ASP.NET Core Web API
在本文中,我们将研究如何测试你的 ASP .NET Core 2.0 Web API 解决方案.我们将了解使用单元测试进行内部测试,使用全新的 ASP .NET Core 的集成测试框架来进行外部测试 ...
- 配置实体框架DbContext的可扩展方案
介绍 在ASP.NET Core Web应用程序中配置DbContext时,通常使用如下扩展方法:AddDbContext services.AddDbContext<xxxDbContext& ...
- 在ASP.NET Core 2.0中创建Web API
目录 介绍 先决条件 软件 技能 使用代码 第01步 - 创建项目 第02步 - 安装Nuget包 步骤03 - 添加模型 步骤04 - 添加控制器 步骤05 - 设置依赖注入 步骤06 - 运行We ...
最新文章
- HTTP头入门到精通(每一个HTTP消息头解释)
- 《C#精彩实例教程》小组阅读07 -- C#字符与字符串
- mysql查看数据文件ibdata_如何从 ibdata文件 恢复 MySQL 数据库
- 创建第二个 local network - 每天5分钟玩转 OpenStack(84)
- 第三十章 elk(1) - 第一种架构(最简架构)
- 无符号定点数加法运算的VHDL描述
- java多次点击时事件_click事件的累加绑定,绑定一次点击事件,执行多次
- Cisco ACS AAA服务器导入华为私有属性
- LeetCode(804)——唯一摩尔斯密码词(JavaScript)
- 【信息系统项目管理师】第4章-项目整体管理 知识点详细整理
- gitlab 删除分支_idea gitlab 分支 pull、push 实践笔记
- javascript循环事件只响应最后一次的问题处理
- Deploy Apache Flink Natively on YARN/Kubernetes
- 计算机文献检索过程,计算机文献检索的基本方法与策略
- Unity3D手机游戏开发
- CNN之Xception Keras实现模型训练
- 去面试却被问的哑口无言,是不是踏入了机器学习误区
- 电脑饥荒服务器未响应,《饥荒》联机版常见问题及解决方法一览
- Windows 事件日志分析管理
- 使用eclipse和JavaFX Scene Builder进行快速构建JavaFX应用程序