Overview

When setting up a custom WebApplicationFactory to allow for testing a REST based API end point you may have the requirement of always needing to send a specific header in with the request. This can be in relation to a specific user agent or an api key etc. depending on the implementation. Adding this into the client in every test can get repeatative so in this post I will show you a way of reducing code duplication.

Implementation

To set this up a few parts of the jigsaw are required.

Custom Web Application Factory

The first part of the jigsaw is a custom web application factory. Making a custom factory allows for being explicit about what we are trying to change. The CustomWebApplicationFactory will derive from the Microsoft.AspNetCore.Mvc.Testing.WebApplicationFactory<TEntryPoint> and we specify the Startup class of our web api project. The base WebApplicationFactory can be found in the [Microsoft.AspNetCore.Mvc.Testing][nugetlink] package.

public class CustomWebApplicationFactory : WebApplicationFactory<Startup>
{
    protected override void ConfigureClient(HttpClient client)
    {
        client.DefaultRequestHeaders.Add("My-Header", "My Value Always Expected");
        
        base.ConfigureClient(client);
    }
}

Once we have the factory defined there are many methods which can be overridden and expanded on but the one we are interested is the ConfigureClient method. This method allows us to configure the HttpClient instance which is created when we ask the factory for a client. In the method we get access to the httpclient and then we can set various items on it, including headers, as we would if we were configuring a client to talk to an external end point. At the end of the day it is just a HttpClient talking to a REST api end point.

Setting Up To Test

We now have a custom web application factory but how do we use it?

We start off by creating a test class where we are going to write our tests and add a IClassFixture<> to the class. At this point we can specify the test fixture for the class.

note: I use xUnit.NET for all my testing whether it’s unit or integration testing; I highly recommend!

In a similar way that we can define services and have dependencies injected into them at run time through dependency injection in our applications we can specify a dependency to the test class of the application factory type.


    public class RequestTests : IClassFixture<CustomWebApplicationFactory>
    {
        private readonly HttpClient _client;

        public RequestTests(CustomWebApplicationFactory factory)
        {
            _client = factory.CreateDefaultClient();
        }

Once injected we can now request that a default HttpClient is created. This can be done in the test class constructor or if other settings need to be changed on a test by test basis this create method can be called inside the test methods.

Running the Tests

At this point we have the items setup to call our web api end point so we need a test to execute. As we have got all the infrastructure added we can write the test with minimal fuss.


[Fact]
public async Task Get_Entity()
{
    // Arrange
    var requestId = "11223344";

    // Act
    var result = await _client.GetAsync($"/api/entity/{requestId}");

    // Assert
    result.EnsureSuccessStatusCode();
}

As well as unit tests I like to use the AAA (Arrange, Act, Assert) pattern for writing integration tests as well. As you can see from the above it’s a very simple test but if you debug through into your api controller which deals with the route you will now have access to the header added in the factory.

[HttpGet]
[Route("{id}")]
public async Task<IActionResult> Get(string id)
{
    var header = HttpContext.Request.Headers.TryGetValue("My-Header", out var items);

    return Ok(items);
}

Conclusion

In this post we have created a custom web application factory to allow for overriding the ConfigureClient method which allows for setting custom headers on the httpclient for our integration tests. This is a technique which can be extending to other options you may want to set values on before executing the tests.

Any questions/comments then please contact me on Twitter @WestDiscGolf

Part 1 - Integration Testing with ASP.NET Core 3.1

Part 2 - Integration Testing with ASP.NET Core 3.1 - Testing Your Application

Part 3 - Integration Testing with ASP.NET Core 3.1 - Swapping a dependency

Part 4 - Integration Testing with ASP.NET Core 3.1 - Remove the Boiler Plate

Part 5 - [Integration Testing with ASP.NET Core 3.1 - Swapping a Dependency with Moq][ParkFiveLink]

Part 6 - This Post