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
Other Posts In This Series
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