ASP.NET CORE 2.* 利用集成测试框架覆盖HttpClient相关代码
2019-08-16 15:59
1421 查看
我的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中HttpClient的使用方式
- ASP.NET Core 2.1 : 十三.httpClient.GetAsync 报SSL错误的问题
- (6)ASP.NET Core 中使用IHttpClientFactory发出HTTP请求
- ASP.Net Core2.1中的HttpClientFactory系列二:集成Polly处理瞬态故障
- asp.net core获取HttpContext相关操作
- Asp.net core 学习笔记 ( HttpClient )
- 利用Asp.Net Core的MiddleWare思想处理复杂业务流程
- ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界
- ASP.NET利用HttpHandler实现多扩展名文件下载
- ASP.NET中,客户端利用 ASP.NET AJAX(Atlas)调用服务端方法的代码
- Asp.Net Core IIS发布后PUT、DELETE请求错误405.0 - Method Not Allowed 因为使用了无效方法(HTTP 谓词)
- ASP.NET Core中间件计算Http请求时间示例详解
- asp.net HttpHandler操作Session的函数代码
- ASP.NET中常用功能代码总结(7)——利用Jmail发送和接收邮件
- 利用HttpClient 获取网页数据java代码模版
- Asp.Net Web API 2第四课——HttpClient消息处理器
- HttpModule 实现 ASP.Net (*.aspx) 中文简繁体的自动转换,不用修改原有的任何代码,直接部署即可!
- asp.net利用存储过程分页代码收藏
- Asp.Net Core-几行代码解决Razor中的嵌套if语句
- ASP.NET 2.0 HttpHandler实现生成图片验证码(示例代码下载)