[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(); } } } |
如我们预期,返回了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),我们将立即处理。