Accessing cookies inside unit test in the context of AspNet.TestHost.TestServer on ASP.NET 5 / MVC 6

There is no easy way to access the CookieContainer in response object, which runs integration tags with AspNet.TestHost.TestServer . Cookies must be set using the controller action. What is the best way to achieve this?

  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"]); 

The solution that I see is to expand the TestServer instance, return an instance of the CustomClientHandler : ClientHandler and override the entire process of sending the request in this handler, but it needs to literally change all the logic except for the relatively small TestServer code.

Any best suggestion on how to implement cookie access in response?

+8
source share
2 answers

I have implemented a custom HttpMessageHandler that tracks cookies.

It uses reflection to invoke the actual handler and simply reads / sets the cookie headers.

 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; } } 

And then you create your HttpClient as follows:

 var httpClient = new HttpClient( new TestMessageHandler( server.CreateHandler())); 

TestMessageHandler now tracks cookies.

+2
source

In addition to @Oleh's answer, you can achieve the same result without thinking about new environments such as .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; } } 
0
source

Source: https://habr.com/ru/post/1232148/


All Articles