Testing 在ASP.NET 5/MVC 6上的AspNet.TestHost.TestServer上下文中访问单元测试内部的Cookie
在运行与Testing 在ASP.NET 5/MVC 6上的AspNet.TestHost.TestServer上下文中访问单元测试内部的Cookie,testing,cookies,owin,asp.net-core,asp.net-core-mvc,Testing,Cookies,Owin,Asp.net Core,Asp.net Core Mvc,在运行与AspNet.TestHost.TestServer集成测试的response对象中,没有简单的方法可以访问CookieContainer。Cookie必须由控制器操作设置。实现这一目标的最佳方式是什么 var client = TestServer.Create(app => { app.UseMvc(routes => routes.MapRou
AspNet.TestHost.TestServer
集成测试的response
对象中,没有简单的方法可以访问CookieContainer
。Cookie必须由控制器操作设置。实现这一目标的最佳方式是什么
var client = TestServer.Create(app =>
{
app.UseMvc(routes =>
routes.MapRoute("default", "{controller}/{action}/{id?}"));
app.UseIdentity();
}).CreateClient();
var request = new HttpRequestMessage(HttpMethod.Get, "account/login");
var response = await client.SendAsync(request);
// how to get an access to cookie container ?????????
// response.Cookies prop doesn't exist
Assert.NotEmpty(response.Cookies["auth"]);
我看到的解决方案是扩展TestServer的实例,返回一个类的实例CustomClientHandler:ClientHandler
,并覆盖在该处理程序中发送请求的整个过程,但它实际上需要更改除TestServer相对较小的代码之外的所有逻辑
有没有更好的建议如何在响应中实现对cookie的访问 我已经实现了跟踪Cookie的自定义HttpMessageHandler 它使用反射来调用实际的处理程序,只读取/设置Cookie头
class TestMessageHandler : HttpMessageHandler
{
delegate Task<HttpResponseMessage> HandlerSendAsync(HttpRequestMessage message, CancellationToken token);
private readonly HandlerSendAsync nextDelegate;
private readonly CookieContainer cookies = new System.Net.CookieContainer();
public TestMessageHandler(HttpMessageHandler next)
{
if(next == null) throw new ArgumentNullException(nameof(next));
nextDelegate = (HandlerSendAsync)
next.GetType()
.GetTypeInfo()
.GetMethod("SendAsync", BindingFlags.NonPublic | BindingFlags.Instance)
.CreateDelegate(typeof(HandlerSendAsync), next);
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("Cookie", cookies.GetCookieHeader(request.RequestUri));
var resp = await nextDelegate(request, cancellationToken).ConfigureAwait(false);
if (resp.Headers.TryGetValues("Set-Cookie", out var newCookies))
{
foreach (var item in SetCookieHeaderValue.ParseList(newCookies.ToList()))
{
cookies.Add(request.RequestUri, new Cookie(item.Name, item.Value, item.Path));
}
}
return resp;
}
}
TestMessageHandler现在负责跟踪Cookie。作为@Oleh响应的一个补充,您可以在不考虑.NET 4.6.1+/.NET Core等较新框架的情况下实现相同的功能
public class TestHttpClientHandler : DelegatingHandler
{
[NotNull]
private readonly CookieContainer cookies = new CookieContainer();
public TestHttpClientHandler([NotNull] HttpMessageHandler innerHandler)
: base(innerHandler) { }
[NotNull, ItemNotNull]
protected override async Task<HttpResponseMessage> SendAsync([NotNull] HttpRequestMessage request, CancellationToken ct)
{
Uri requestUri = request.RequestUri;
request.Headers.Add(HeaderNames.Cookie, this.cookies.GetCookieHeader(requestUri));
HttpResponseMessage response = await base.SendAsync(request, ct);
if (response.Headers.TryGetValues(HeaderNames.SetCookie, out IEnumerable<string> setCookieHeaders))
{
foreach (SetCookieHeaderValue cookieHeader in SetCookieHeaderValue.ParseList(setCookieHeaders.ToList()))
{
Cookie cookie = new Cookie(cookieHeader.Name.Value, cookieHeader.Value.Value, cookieHeader.Path.Value);
if (cookieHeader.Expires.HasValue)
{
cookie.Expires = cookieHeader.Expires.Value.DateTime;
}
this.cookies.Add(requestUri, cookie);
}
}
return response;
}
}
公共类TestHttpClientHandler:DelegatingHandler
{
[非空]
私有只读CookieContainer cookies=新CookieContainer();
公共测试HttpClientHandler([NotNull]HttpMessageHandler innerHandler)
:base(innerHandler){}
[NotNull,ItemNotNull]
受保护的覆盖异步任务SendAsync([NotNull]HttpRequestMessage请求,CancellationToken ct)
{
urirequesturi=request.requestUri;
request.Headers.Add(HeaderNames.Cookie,this.cookies.GetCookieHeader(requestUri));
HttpResponseMessage response=等待base.SendAsync(请求,ct);
if(response.Headers.TryGetValues(HeaderNames.SetCookie,out IEnumerable setCookieHeaders))
{
foreach(SetCookieHeaderValue.ParseList(setCookieHeaders.ToList())中的SetCookieHeaderValue cookieHeader)
{
Cookie Cookie=新Cookie(cookieHeader.Name.Value、cookieHeader.Value.Value、cookieHeader.Path.Value);
if(cookieHeader.Expires.HasValue)
{
cookie.Expires=cookieHeader.Expires.Value.DateTime;
}
this.cookies.Add(requestUri,cookie);
}
}
返回响应;
}
}
对于dotnet核心集成测试方法,如文档中所述,您可以使用以下代码获取cookie:
public class CookieTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public CookieTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task GetPage_ShouldSetCookie_CookieSet()
{
using (var client = _factory.CreateClient())
{
var response = await client.GetAsync("/cookie_setting_url");
response.EnsureSuccessStatusCode();
//or other assertions
Assert.True(response.Headers.TryGetValues(HeaderNames.SetCookie, out IEnumerable<string> cookies));
}
}
}
公共类Cookiets:IClassFixture
{
私有只读WebApplicationFactory\u工厂;
公共烹饪测试(WebApplicationFactory)
{
_工厂=工厂;
}
[事实]
公共异步任务GetPage\u ShouldSetCookie\u CookieSet()
{
使用(var client=\u factory.CreateClient())
{
var response=wait client.GetAsync(“/cookie\u setting\u url”);
response.EnsureSuccessStatusCode();
//或其他断言
True(response.Headers.TryGetValues(HeaderNames.SetCookie,out IEnumerable cookies));
}
}
}
Cookies只是标题。下面是一个从响应中获取cookie并将其添加到下一个请求的示例:即使我只执行var h=testServer.CreateHandler();_client1=新的HttpClient(h,true);任何请求都会导致:提供了无效的请求URI。请求URI必须是绝对URI或必须设置基地址。所以,我想这不适用于TestServer@DmitryGusarov下面是我使用的代码:var-client=new-HttpClient(new-TestMessageHandler(server.CreateHandler()){BaseAddress=server.BaseAddress}
,我通常为我的所有客户机指定基址,但在答案中使用了它。这非常有效。这是一个很好的解决一个非平凡问题的方法,谢谢你的贡献!
public class CookieTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly WebApplicationFactory<Startup> _factory;
public CookieTests(WebApplicationFactory<Startup> factory)
{
_factory = factory;
}
[Fact]
public async Task GetPage_ShouldSetCookie_CookieSet()
{
using (var client = _factory.CreateClient())
{
var response = await client.GetAsync("/cookie_setting_url");
response.EnsureSuccessStatusCode();
//or other assertions
Assert.True(response.Headers.TryGetValues(HeaderNames.SetCookie, out IEnumerable<string> cookies));
}
}
}