Every ASP .NET Core request processing pipeline has one or more than one middleware components. In this article, let’s have a look at how to test the middleware components / classes using unit tests.
You can also refer my previous articles throwing more light on how to create custom middlewares.
Why unit test middleware?
Many of us have a view that the ASP .NET Core layer need not be unit tested in most of the cases as it is very hard to mock all the dependencies and in most of the cases, it may not be worth.
In some cases it might be true, in my opinion, there is no single universal answer to this question. It always has to be a pragmatic decision.
In some cases, the middleware might be very simple and straightforward enough (like handling static files), which you may not want to unit test. In some other cases, the middleware might be performing some fairly complex logic (e.g. handling unhandled exceptions, or logging requests). In those cases, you want to unit test the logic.
When you are in doubt, then also, you may want to write the unit tests. Why ? Because unit tests help future developers (or your future self) in understanding the requirements (if written carefully) and they provide quickest possible feedback to the code changes done by you.
The decision has to be thought thoroughly. If unit testing is not done carefully, instead of providing you insights and help, it may end up consuming a lot of time in maintaining those tests.
The middleware for this demo is simple and it is just adds a cookie
DummyCookie to the response – if it is not already present in the request. It is not terminal middleware so after adding cookie to the response it just hands over response to the next middleware.
Create the middleware extension as shown below. The below method would be used to configure middleware in the request pipeline.
Now, after this, let’s configure this middleware in the request processing pipeline as shown below:
|public class Startup|
|// This method gets called by the runtime. Use this method to add services to the container.|
|// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940|
|public void ConfigureServices(IServiceCollection services)|
|// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.|
|public void Configure(IApplicationBuilder app, IWebHostEnvironment env)|
|app.Run(async context =>|
|await context.Response.WriteAsync("App Response");|
Run the application and ensure that everything is working as expected.
The Test Proejct
The approach on high level is:
- Mock all dependencies and Setup DI.
- Instantiate the Middleware
- context: pass
DefaultHttpContextobject to it
- next: pass a dummy terminal middleware to it to end the response
- context: pass
- Assert the changes in
Below are the command lines to create the xUnit test project and to add reference of web app project into the test project.
|## Go to the directory which contains the web app project|
|## Navigate to parent directory of web app project directory|
|## Create directory for test project|
|## Move to the test project directory|
|## Create xUnit test proejct of same name (FirstWebApp.Tests)|
|dotnet new xunit|
|## Add reference of Web App project to the test project|
|dotnet add reference ..\FirstWebApp\FirstWebApp.csproj|
|## Move to the parent directory|
|## Open Visual Studio Code|
Let’s write the unit test
There should be at least two unit test to ensure that middleware is functioning as expected:
- If incoming request does not have cookie, it would be added to response
- If incoming request had the cookie, no cookie would be set in response
For this demo, we are going to have look at only first unit test. This unit test will have three important steps:
- Arrange: It creates
DefaultHttpContextobject and sets few properties like path to some valid
Response.Bodyis set to an empty memory stream
- Act: It creates a new instance of middleware. A dummy delegate is passed to the middleware. This dummy delegate writes a string to the response. Then the middleware is invoked with instance of
DefaultHttpContextobject created in first step.
- Assert: checks if the response has valid cookie and response body has the value written by the dummy request delegate.
Below is the code for the unit test:
I hope you found this information to be helpful. Let me know your thoughts.