ASP.NET Core 2.1 middlewares part 2: Unit test a custom middleware
- ASP.NET Core 2.1 middlewares part 1: Building a custom middleware
- ASP.NET Core 2.1 middlewares part 2: Unit test a custom middleware
How to unit test a middleware ?
It’s very easy to unit test a middleware in ASP.NET Core.
There three important things to understand here.
First the Invoke method takes in parameter an HttpContext instance.
We all know how it’s painful to mock an HttpContext… We don’t need! ASP.NET Core provide a “fake” HttpContext named DefaultHttpContext. Feeling better now ? 🙂
Second thing to know, if you need to unit test the Response body property you have to initialize it tourslef like this:
var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream();
and just before reading the content, reset the body’s stream position back to 0.
context.Response.Body.Seek(0, SeekOrigin.Begin);
And finally, the RequestDelegate object passed in parameter of the middleware’s constructor is simply a delegate, Action exactly.
We are ready to unit test our custom middleware
In these scenarii, we will use XUnit and FluentAssertion
Case 1: scenario with a custom error:
public class CustomExceptionMiddlewareTests { [Fact] public async Task WhenACustomExceptionIsRaised_CustomExceptionMiddlewareShouldHandleItToCustomErrorResponseAndCorrectHttpStatus() { // Arrange var middleware = new CustomExceptionMiddleware((innerHttpContext) => { throw new NotFoundCustomException("Test", "Test"); }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var objResponse = JsonConvert.DeserializeObject<CustomErrorResponse>(streamText); //Assert objResponse .Should() .BeEquivalentTo(new CustomErrorResponse { Message = "Test", Description = "Test" }); context.Response.StatusCode .Should() .Be((int)HttpStatusCode.NotFound); } }
Case 2: scenario with an unhandled error:
public class CustomExceptionMiddlewareTests { [Fact] public async Task WhenAnUnExpectedExceptionIsRaised_CustomExceptionMiddlewareShouldHandleItToCustomErrorResponseAndInternalServerErrorHttpStatus() { // Arrange var middleware = new CustomExceptionMiddleware(next: (innerHttpContext) => { throw new Exception("Test"); }); var context = new DefaultHttpContext(); context.Response.Body = new MemoryStream(); //Act await middleware.Invoke(context); context.Response.Body.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(context.Response.Body); var streamText = reader.ReadToEnd(); var objResponse = JsonConvert.DeserializeObject<CustomErrorResponse>(streamText); //Assert objResponse .Should() .BeEquivalentTo(new CustomErrorResponse { Message = "Unexpected error", Description = "Unexpected error" }); context.Response.StatusCode .Should() .Be((int)HttpStatusCode.InternalServerError); } }
Easy isn’t it ? 😉