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