Introduction

The Just Eat HttpClient Interception library might not be that well known but personally I think it’s super powerful when it comes to testing strongly typed clients which rely on HttpClient or for end to end integration tests where responses are needed from 3rd party REST end points and network connectivity to the 3rd party can’t be a factor in your test suite execution.

In this post I am going to give a high level overview of what the library is and how to get started with it. I am also going to show how you can set up an example through code.

Overview

If a service relies on your strongly typed client sometimes this is mocked completely for testing. When testing a class or service which relies on a HttpClient instance setting up mock responses can be tricky. To allow for testing you have to manually setup a DelegatingHandler and add it into the HttpClient call chain. What this achieves is the ability to intercept the HttpRequestMessage and return a well known HttpResponseMessage. Doing this manually across a number of tests can make your “Arrange” phase of tests cumbersome and brittle.

The Just Eat HttpClient Interception library does essentially that for you however it allows for additional flexibility in setting up the stock responses. It also allows for targetted matching of requests to return specific responses for specific scenarios in your tests. This makes the “Arrange” phase of your tests both clearer and improves maintainability for the future.

So how can we get started? Let’s find out!

Nuget Package

First off you will need to reference the nuget package in your unit testing project. This package is testing framework agnostic so can work with any runner. All the examples will be using xUnit as this is my preferred unit testing framework.

<PackageReference Include="JustEat.HttpClientInterception" Version="3.1.0" />

My First Request

Once your testing project has the package referenced and restored you can now start using it. In the example below we are going to setup a simple GET request to respond to. Once matched on the specified parameters it will return a specific response in JSON format.

var builder = new HttpRequestInterceptionBuilder()

We start off by creating an HttpRequestInterceptionBuilder instance. Using the builder pattern this is where the attributes of the request are built up.

.ForHost("api.github.com")
.ForPath("users/westdiscgolf")
.ForHttps()
.ForMethod(HttpMethod.Get)

The next 4 method calls above start to specify what the call needs to match on. Above we are specifying that the host needs to match “api.github.com”, the path of the request needs to match “users/westdiscgolf”, the scheme of the request to “https” and the http method of “Get”. These are the items on which the test request is matched on. If the request matches all of these items then the specified response will be returned. To be more specific with the request allows for more subtilties and differences when requiring a number of requests to be setup per test.

.WithJsonContent(new { login = "WestDiscGolf", 
    name = "Adam Storr" });

And finally the known content response is specified. This is the json structure which will be returned on a successful match from the test request. Under the hood this takes the object specified, in this example an anonymous type, and converts it using Json.NET.

var options = new HttpClientInterceptorOptions().Register(builder);
var client = options.CreateHttpClient();

Once the request builder setup is complete we need to add it to the HttpClientInterceptorOptions instance and create the HttpClient request instance to use in our tests. Now we have a “proper” HttpClient instance all setup to pass into our SUT, or System Under Test, on which the Act and Assert phases of the test can use.

Full Unit Test

[Fact]
public async Task Basic_Interception()
{
    // Arrange
    var builder = new HttpRequestInterceptionBuilder()
        .ForHost("api.github.com")
        .ForPath("users/westdiscgolf")
        .ForHttps()
        .ForMethod(HttpMethod.Get)
        .WithJsonContent(new { login = "WestDiscGolf", 
            name = "Adam Storr" });

    var options = new HttpClientInterceptorOptions().Register(builder);
    var client = options.CreateHttpClient();

    // Act
    var response = await client.GetStringAsync("https://api.github.com/users/westdiscgolf");

    // Assert
    response.Should().ContainAll("login", "WestDiscGolf", "name", "Adam Storr");
}

As you can see from the above the “Arrange” phase is as described through the post. We can then make a “GetStringAsync” request using the HttpClient instance with the specified uri. This uri is made up of all the aspects which we want to match on; schema, host, path, and will response to a Get request.

In the response returned we can see that it has the same data points as the Json content we setup in the “Arrange” phase however returned to us as a Json string. In the Assert phase of the test the example is using some basic string checking to show the items are returned. In a more robust test I would use a strongly typed model class, defined in the test project, and check the values were mapping correctly.

Basic Overview Talk

I gave a 15 minute lightning talk at .NET Oxford in April ‘21 about this library. If you are interested in hearing more about this library in a short presentation please check it out here.

Conclusion

In this post we have reviewed getting started with the Just Eat HttpClient Interception library. We have walked through a basic example of a Get request to see my GitHub profile and a test response back from it. We have shown that making the matched response will return the specified content payload in the setup builder to allow for scenario testing. In future posts I hope to explore the library more so please subscribe to my rss feed (link below) and reach out to me on Twitter @WestDiscGolf if you have any comments.