DEV Community

Cover image for Unit testing a custom middleware in ASP.NET Core with Interface
Harshal Suthar
Harshal Suthar

Posted on • Originally published at ifourtechnolab.com

Unit testing a custom middleware in ASP.NET Core with Interface

What is unit test?

A unit test is a type of testing.It is the Small Part of code that can be logically in a Program and test that code is work properly that is testing.

The latest versions of unit testing can be found in frameworks like JUnit, or testing tools like Test Complete. You will also find SUnit, which is the mother of all unit testing frameworks it is created by Kent Back.

How does the tests look like?

A unit can be almost anything you want it is, a line of code or a method, and a class. Smaller tests give you a more detail view of how your code is performing. There is also the practical aspect that when you test very small units, your tests can be run fast; like so many tests in a second fast.

Consider this sample code

def divider (x, y)
return x/y
End

Enter fullscreen mode Exit fullscreen mode

This example is simple, but it gives you an idea of what I mean by small. Small tests also have the benefit of building it harder to cross-systems from code into a database, or 3rd party system. There is not anything wrong with crossing systems, but there is a result like gradually slowing your tests, a test suite that takes hours to run.

What is Middleware?

Middleware’s are a fundamental part of an ASP.NET application, introduced from day one. They are executed in the order they are added on every request and could be considered similar to the HTTP Handlers and HTTP Modules of the classic ASP.NET. Since middleware’s can execute code before or after calling subsequent within the pipeline, they're considered ideal for plenty of varied application features, including exception handling, logging, authentication, etc.

Read More: Ultimate Guide For Implementing Repository Pattern And Unit Of Work For .net Core

Middleware is often tested in isolation with Test Server. It allows you to instantiate an app pipeline containing only the components that you simply got to test.

Advantages of Middleware

  • Requests are sent in-memory instead of being serialized over the network.
  • Exceptions within the middleware can flow directly back to the calling test.
  • It's possible to customize server data structures, like HttpContext, directly within the test.

Middleware’s offer a more powerful and flexible solution and for that, they need to be tested! Thankfully there's how to try to that so let's first see what we are getting to test then just get in there to Example:

You can need to Install Microsoft.AspNetCore.Testhst

First of All, you can need to Configure the processing pipeline to use the middleware for the test. part of program configure Processing pipeline is shown below.

[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
 {
using varhst = await new hstBuilder().ConfigureWebhst(webBuilder =>
 {
webBuilder.UseTestServer().ConfigureServices(services =>
 {
services.AddMyServices();
 })
.Configure(app =>
 {
app.UseMiddleware<mymiddleware>();
  });
  })
.StartAsync();
}</mymiddleware>

Enter fullscreen mode Exit fullscreen mode

After that you need to send requests with the HttpClient sample code is below.

[Fact]
 public async Task MiddlewareTest_ReturnsNotFoundForRequest()
 {
using varhst = await new hstBuilder().ConfigureWebhst(webBuilder =>
 {
webBuilder.UseTestServer().ConfigureServices(services =>
 {
services.AddMyServices();
 })
.Configure(app =>
 {
app.UseMiddleware<mymiddleware>();
 });
 })
.StartAsync();
var response = await hst.GetTestClient().GetAsync("/");
}</mymiddleware>

Enter fullscreen mode Exit fullscreen mode

Assert the result and make an assertion of the opposite of the result that you expect. An embryonic run with a false positive assertion confirms that the test fails. when the middleware is performing Truly. Start test and confirm that the test is failed.

In this example, the middleware returns a 404-status code which is NOT FOUND code when the root endpoint is requested. Make the first one test run with Assert.NotEqual (); which should be fail.

[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
 {
using varhst = await new hstBuilder().ConfigureWebhst(webBuilder =>
 {
webBuilder.UseTestServer().ConfigureServices(services =>
 {
services.AddMyServices();
 })
.Configure(app =>
 {
app.UseMiddleware<mymiddleware>();
 });
 })
.StartAsync();
var response = await hst.GetTestClient().GetAsync("/");
Assert.NotEqual(HttpStatusCode.NotFound, response.StatusCode);
 }</mymiddleware>

Enter fullscreen mode Exit fullscreen mode

Change the assertion for test the middleware under normal operating ambiance. The final test uses Assert.Equal( );. Run the test a second time to confirm that it was successful.

[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
  {
using varhst = await new hstBuilder()
.ConfigureWebhst(webBuilder =>
  {
webBuilder.UseTestServer().ConfigureServices(services =>
  {
services.AddMyServices();
  })
.Configure(app =>
  {
app.UseMiddleware<mymiddleware>();
  });
  })
.StartAsync();
var response = await hst.GetTestClient().GetAsync("/");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}</mymiddleware>

Enter fullscreen mode Exit fullscreen mode

Looking to Hire Dedicated .NET Core Developer? Contact Now.

Send requests with HttpContext

A test app is also sending a request using SendAsync(Action, CancellationToken). In this example, several checks are made when https:// example. com/A/Path/?and=query is done by the middleware.

[Fact]
public async Task TestMiddleware_ExpectedResponse()
 {
using varhst = await new hstBuilder()
.ConfigureWebhst(webBuilder =>
 {
webBuilder.UseTestServer().ConfigureServices(services =>
 {
services.AddMyServices();
 })
.Configure(app =>
 {
app.UseMiddleware<mymiddleware>();
 });
 })
.StartAsync();
var server = hst.GetTestServer();
server.BaseAddress = new Uri("https://example.com/A/Path/");
var context = await server.SendAsync(c =>
 {
c.Request.Method = HttpMethods.Post;
c.Request.Path = "/and/file.txt";
c.Request.QueryString = new QueryString("?and=query");
 });
Assert.True(context.RequestAborted.CanBeCanceled);
Assert.Equal(HttpProtocol.Http11, context.Request.Protocol);
Assert.Equal("POST", context.Request.Method);
Assert.Equal("https", context.Request.Scheme);
Assert.Equal("example.com", context.Request.hst.Value);
Assert.Equal("/A/Path", context.Request.PathBase.Value);
Assert.Equal("/and/file.txt", context.Request.Path.Value);
Assert.Equal("?and=query", context.Request.QueryString.Value);
Assert.NotNull(context.Request.Body);
Assert.NotNull(context.Request.Headers);
Assert.NotNull(context.Response.Headers);
Assert.NotNull(context.Response.Body);
Assert.Equal(404, context.Response.StatusCode);
Assert.Null(context.Features.Get<ihttpresponsefeature>().ReasonPhrase);
 }
</ihttpresponsefeature></mymiddleware>

Enter fullscreen mode Exit fullscreen mode

SendAsync allow the direct configuration of an HttpContext object instead of using the HttpClient abstractions. Use SendAsync to control structures only available on the server, like HttpContext.Items or HttpContext.Features.

As with the Previous example that tested for a 404 - Not Found response, check the other for every assert statement within the preceding test. The check confirms that the test fails correctly when the middleware is working normally. After you've confirmed that the false-positive test works, set the ultimate assert statements for the expected conditions and values of the test. Run it again to verify that the test passes.

Conclusion

Using Middleware unit testing you can test parts of code which is placed in program. You can also get more detail result of your testing. Using these you can customize data structures, like HttpContext, directly within the test. You can test from both sides correct or wrong.We hope this blog will be helpful for you to understand concept of unit testing a custom middleware in ASP.NET Core.

Top comments (0)