I'm trying to use the DefaultHttpContext
object to unit test my exception handling middleware.
My test method looks like this:
[Fact]
public async Task Invoke_ProductionNonSuredException_ReturnsProductionRequestError()
{
var logger = new Mock<ILogger<ExceptionHandlerMiddleware>>();
var middleWare = new ExceptionHandlerMiddleware(next: async (innerHttpContext) =>
{
await Task.Run(() =>
{
throw new Exception();
});
}, logger: logger.Object);
var mockEnv = new Mock<IHostingEnvironment>();
mockEnv.Setup(u => u.EnvironmentName).Returns("Production");
var context = new DefaultHttpContext();
await middleWare.Invoke(context, mockEnv.Object);
var reader = new StreamReader(context.Response.Body);
var streamText = reader.ReadToEnd();
//TODO: write assert that checks streamtext is the expected production return type and not the verbose development environment version.
}
In my middleware, I am writing to the context like this:
public static Task WriteResponse(HttpContext context, HttpStatusCode statusCode, object responseData, Formatting jsonFormatting)
{
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)statusCode;
return context.Response.WriteAsync(JsonConvert.SerializeObject(responseData, jsonFormatting));
}
To give you more insight into the middleware approach I've taken, I'm taking the approach found in this answer here.
Works fine when the app is running it's normal pipeline. However, using the DefaultHttpContext method in the test, the response body always comes back empty, and ContentLength is null. Thus, my streamText
variable in the test is an empty string.
Is it possible to inspect what the middleware is writing to the context in this situation? Is this the appropriate way, or is there a better way.
Consider setting the body yourself so that you have control of the stream
Comment provided by @AndrewStanton-Nurse
The
Response.Body
stream inDefaultHttpContext
isStream.Null
, which is a stream that ignores all reads/writes. You need to set the Stream yourself before calling the method.
Further - This will now allow the body to be set, but in order to read it correctly we must set the pointer to the beginning as per this answer, before using the StreamReader.
//...code removed for brevity
var context = new DefaultHttpContext();
context.Response.Body = new MemoryStream();
await middleWare.Invoke(context, mockEnv.Object);
context.Response.Body.Seek(0, SeekOrigin.Begin);
var reader = new StreamReader(context.Response.Body);
var streamText = reader.ReadToEnd();
//...code removed for brevity
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With