Testing the response body of middleware in ASP.NET Core
Testing custom middleware in ASP.NET Core is very easy (e.g. for the response status code), but it’s a bit tricky if you want to test the response body because
DefaultHttpContext
uses a Null-Stream for the body and thus is always empty. Creating an implementation of HttpContext is way too much overhead, but you can use a custom Stream object for the response body of DefaultHttpContext
. Here is how you do it. // use this memory stream for the response body var responseBodyStream = new MemoryStream(); var context = new DefaultHttpContext(); context.Features.Get<IHttpResponseFeature>().Body = responseBodyStream; var middleware = new MyMiddleware(async (c) => { await Task.Delay(0); }); await middleware.Invoke(context); // reset the position responseBodyStream.Position = 0; // read the body string bodyContent = new StreamReader(context.Response.Body).ReadToEnd();The trick is to access the
IHttpResponseFeature
of the DefaultHttpContext
and to use a custom MemoryStream
. The memory stream can be read after invoking the middleware, you just need to set the position back to zero. Here is a full example of a custom middleware with tests:// custom middleware - returns "Hello World !!!" for a specific header public class HelloWorldMiddleware { private readonly RequestDelegate _next; public HelloWorldMiddleware(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { bool contains = context.Request.Headers.TryGetValue( "HelloWorld", out StringValues values); // if header contains HelloWorld=true, return custom response if (contains && values == "true") { var result = "Hello World !!!"; await context.Response.WriteAsync(result); } else { await _next(context); } } } // the test class - make sure the correct response is returned // for the "HelloWorld" header, but does nothing for everything else public class HelloWorldMiddlewareTest { [Fact] public async Task Header_WhenContainsHelloWorld_ResponseBodyIsHelloWorld() { var responseBodyStream = new MemoryStream(); var nextDelegateCalled = false; var context = new DefaultHttpContext(); context.Request.Headers.Add("HelloWorld", "true"); // use a custom stream for the response body context.Features.Get<IHttpResponseFeature>().Body = responseBodyStream; var middleware = new HelloWorldMiddleware( async (c) => { await Task.Delay(0); nextDelegateCalled = true; }); await middleware.Invoke(context); // reset position before reading responseBodyStream.Position = 0; string bodyContent = new StreamReader(context.Response.Body).ReadToEnd(); // _next should not be called Assert.False(nextDelegateCalled); // and the body should be: Assert.Equal("Hello World !!!", bodyContent); } [Fact] public async Task Header_WhenNotContainsHelloWorld_CallsNextDelegate() { var responseBodyStream = new MemoryStream(); var nextDelegateCalled = false; var context = new DefaultHttpContext(); context.Features.Get<IHttpResponseFeature>().Body = responseBodyStream; var middleware = new HelloWorldMiddleware( async (c) => { await Task.Delay(0); nextDelegateCalled = true; }); await middleware.Invoke(context); responseBodyStream.Position = 0; string bodyContent = new StreamReader(context.Response.Body).ReadToEnd(); // _next delegate must be called Assert.True(nextDelegateCalled); Assert.NotEqual("Hello world !!!", bodyContent); } }
Comments
Post a Comment