In last few articles, I have been trying to go through all the common and important aspects related to ASP .NET Core middleware.
If you are interested, below are the links to previous posts:
- Custom middlewares in ASP .NET Core 5
- Branching the request pipeline in ASP .NET Core 5
- How to Unit Test ASP .NET Core Middleware ?
In previous post, we have seen the approach which is outlined again as:
- Mock all dependencies and Setup DI.
- Instantiate the Middleware using
- context: pass
DefaultHttpContextobject to it
- next: pass a dummy terminal middleware to it to end the response
- context: pass
- Assert the changes in
So, in the above approach, the middleware instance is required to be created using new operator. It does not make use of request process pipeline to instantiate the middleware.
But what if, you want to configure the request process pipeline similar to as in ASP .NET Core web application, which will have either one or more than one middleware in the pipeline ?
The NuGet Package
The Microsoft.AspNetCore.TestHost Package helps in this. It helps you to setup a lightweight TestServer for unit tests. The unit tests can create the web host and send the custom requests to the TestServer. This will mimic the same behavior of sending requests from external client.
The advantage obviously is better readable request pipeline, which contains one or more middleware components.
Is it really a unit test ?
But some of us may say that if we include multiple middleware in the request pipeline, would it still be called a unit test ? Well, people may have different opinions about what is the real meaning of the word
unit from the concept of unit tests.
Some of us may say, unit for testing is class, some of us may say group of classes or some may say it is assembly and some may say the unit is a requirement.
I personally believe, a unit test should test a single requirement which is implemented by the design. The design, here means, a set of classes which implement a unit of requirement and they must be part of same single process.
So, a unit test is the test which tests a single implemented requirement. So, it may focus on single class or set of classes, but the asserts should always define the requirement and not the design.
The Middleware and Pipeline
For the demo purpose, we are going to use the same middleware which I used in the previous article. It adds a cookie to the response if it is not already present in the request.
The request process pipeline is as shown below:
The Test Project
Below is the set of .NET CLI commands to create the test project. It creates project, add reference of WebApp project to the test project. Then it adds the required NuGet package – the Microsoft.AspNetCore.TestHost Package – to the test project.
Below code snippet shows two classes:
- Setup class, which initializes the TestServer instance using a request pipeline defined in TestStartup class.
- TestStartup class, which defines the request pipeline required for tests. For the demo, the pipeline has only one middleware and a sample mock terminal middleware.
The test class is simple. It just has a single unit test to check if cookie is added to the response. The unit test
- Creates the TestServer instance
- Creates a context and sends a request to TestServer
- The API returns HttpContext
- Test then asserts based on values present in the output HttpContext
There are few things which needs to be noted, before designing the unit tests using this package.
These requests are sent in memory so it does not test the serialization requirements. Also, the exceptions raised by the TestServer web host can be caught by the calling test.
As we have seen in above examples, it is possible with this NuGet Package to customize server data structures, such as HttpContext, directly in the test.
Also, this same NuGet package can be used for writing integration tests (or API tests).
I hope you found this information useful. Let me know your thoughts.