Unit testing a custom middleware in ASP.NET Core API

Middlewares are a fundamental part of any ASP.NET Core application, introduced from day one. They are executed in the order they are added on every request, and could be considered similar to the HttpHandlers and HttpModules of the classic ASP.NET. Since middlewares can execute code before or after calling the next in the pipeline, they are considered ideal for a ton of various application features, including exception handling, logging, authentication etc.

You can learn more about middlewares by learning how to create a simple exception handling middleware.

Middlewares offer a powerful and flexible solution and for that, they need to be tested! Thankfully there is a way to do that so let’s first see what we are going to test and then just get in to it (middleware taken from Microsoft Docs):

What it actually does is setting up the current culture using the query string from HttpContext. That is nice and useful, but HttpContext is notoriously difficult and dangerous to mock because it is so easy to take a direct dependency on it. I ‘ve even read somewhere that mocking HttpContext is like trying to calculate the last digit of pi: when you think you are done you ‘ll have more.

HttpContext encapsulates all HTTP-specific information about an individual HTTP request. It is the biggest object made by man.

To the rescue for this, we have DefaultHttpContext. Nothing to mock, saved from messing up with login information, it’s there waiting to be used. The only thing to keep in mind is the Response.Body property. The Response.Body stream in DefaultHttpContext is Stream.Null, which is a stream that just ignores all reads/writes. No exceptions, no nothing if you use it, just a “talk to the hand” attitude! Solution of course, to setup the Stream ourselves before calling the method:

Now that we found DefaultHttpContext and know how to use it, let’s just write a unit test to check the default current culture:

Comments are relieving as to what is happening: We are passing a RequestDelegate as the next argument of the RequestCultureMiddleware constructor, that writes in the response the two letter ISO language name of the culture we set. In simple words, if the RequestCultureMiddleware works correctly all next middlewares in the pipeline after it, should have their culture set to whatever the user sent as a query string.

And let’s test exactly that now:

And that was it! Easy right? Happy and safe middlewaring everybody!