使用Microsoft.AspNetCore.TestHost进行完整的功能测试

发表于:2018-9-25 10:27

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:huanent    来源:博客园

分享:

  [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认证
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Threading.Tasks;
  using Microsoft.AspNetCore.Builder;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.Extensions.Configuration;
  using Microsoft.Extensions.DependencyInjection;
  using Microsoft.Extensions.Logging;
  using Microsoft.Extensions.Options;
  using Microsoft.AspNetCore.Authentication.Cookies;
  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需要授权访问
  using Microsoft.AspNetCore.Authentication;
  using Microsoft.AspNetCore.Authentication.Cookies;
  using Microsoft.AspNetCore.Authorization;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.Mvc;
  using System.Collections.Generic;
  using System.Security.Claims;
  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
  using AspnetCoreFunctionalTestDemo;
  using Microsoft.AspNetCore;
  using Microsoft.AspNetCore.Hosting;
  using Microsoft.AspNetCore.TestHost;
  using Microsoft.Extensions.PlatformAbstractions;
  using Newtonsoft.Json;
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Net;
  using System.Net.Http;
  using System.Reflection;
  using System.Text;
  using System.Threading.Tasks;
  using Xunit;
  using static Microsoft.AspNetCore.WebSockets.Internal.Constants;
  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了。

    上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。

22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号