Integration tests without API dependencies with ASP.NET Core and WireMock.Net
Tags: testing, dotnet, csharp, webdev
Published: 2022-12-20 10:31:03

## Introduction
Although there are many definitions about the scope of an integration test, Martin Fowler defines Narrow integration tests, where the integration with other systems are tested using mocks, and Broad integration tests, where they communicate using real APIs.

In this post, I'll explain how to create mocks for HTTP APIs in narrow integration tests using the [WireMock.Net](https://github.com/WireMock-Net/WireMock.Net) library.

## What should we mock?

Vladimir Khorikov has a concept of managed dependencies and unmanaged dependencies, which I consider complementary to Martin Fowler's, to choose what should be to mocked.

Managed dependencies are external systems controlled by us and accessed only by our application (for example, a database). On the other side, unmanaged dependencies are external systems not controlled by us or also accessed by other applications (like a third party API or a message broker).

Vladimir says that we should test our system against managed dependencies, while mocking unmanaged dependencies. I believe this definition is more like a guideline than a rule. For example, in a scenario where our application posts in a message broker for other system to read, that is, the message broker is an unmanaged dependency, we could test the integration with the message broker to validate that the message is being written in the right format (according to contract). This can have value if we want to test if updates to the library used to communicate with the message broker didn't introduce breaking changes in the message.

## Why use mocks?

The reason we use integration tests is to test our components (or classes), which are tested independently in unit tests, working in communication with each other. When we interact with an API, we follow a protocol and trust a contract of communication, that is, that the API will accept parameters X as input and will return an response Y.

That way, the inner works of that external API is not in the scope of our integration tests.

This doesn't remove the requirement of functional tests; it only reduces the amount of those tests, which are more expensive to execute.

Reducing the integration tests only to our application, we have some benefits:

- Speed of the tests, because we remove the network latency;
- No need of data in external systems to execute the tests;
- Reduced brittleness of the tests, that could break in case of the external API instability or external data that changed;
- More trust in the test results.

## Using WireMock<span>.</span>Net
In this example, I've built an API that consumes the PokéAPI service to look for a Pokémon data and return it to the client.

![Diagram of the API](https://blog.genezini.com/p/integration-tests-without-api-dependencies-with-asp.net-core-and-wiremock.net/images/Diagram1.png)

### Controller

The controller is simple and use the [Refit](https://github.com/reactiveui/refit) library to abstract the PokéAPI call and then, returns the data.

```csharp
using Microsoft.AspNetCore.Mvc;
using Refit;

namespace PokemonInfoAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class PokemonInfoController : ControllerBase
    {
        private readonly IConfiguration _configuration;

        public PokemonInfoController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        [HttpGet("{pokemonName}")]
        public async Task<ActionResult<PokemonInfo>> GetAsync(string pokemonName)
        {
            try
            {
                var pokeApi = RestService.For<IPokeApi>(_configuration["PokeApiBaseUrl"]);

                return Ok(await pokeApi.GetPokemonInfo(pokemonName));
            }
            catch (ApiException ex)
            {
                if (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
                {
                    return NotFound();
                }

                return StatusCode(500);
            }
        }
    }
}
```

### Default integration test

We start with a default integration test, using ASP.NET Core's WebApplicationFactory class.
The test creates an instance of our application e makes a request to the `/pokemoninfo` endpoint with the parameter `charmander`. For now, our test will call the PokéAPI.

> 💡 **You can use any class of your API project to instanciate the `WebApplicationFactory`** in your tests. If you're using top-level statements in your application, you can use a controller class. For example, `WebApplicationFactory<PokemonInfoController>`.

```csharp
using FluentAssertions;
using Microsoft.AspNetCore.Mvc.Testing;
using System.Net;
using System.Text.Json;

namespace PokemonInfoAPI.IntegrationTests
{
    public class PokemonInfoTests: IClassFixture<WebApplicationFactory<Program>>
    {
        private readonly WebApplicationFactory<Program> _factory;

        public PokemonInfoTests(WebApplicationFactory<Program> factory)
        {
            _factory = factory;
        }

        [Fact]
        public async Task Get_Existing_Pokemon_Returns_200()
        {
            //Arrange
            var HttpClient = Factory.CreateClient();

            //Act
            var HttpResponse = await HttpClient.GetAsync("/pokemoninfo/charmander");

            //Assert
            HttpResponse.StatusCode.Should().Be(HttpStatusCode.OK);

            var ResponseJson = await HttpResponse.Content.ReadAsStringAsync();
            var PokemonInfo = JsonSerializer.Deserialize<PokemonInfo>(ResponseJson);

            PokemonInfo.Should().BeEquivalentTo(ResponseObj);
        }
    }
}
```

### Setting up a mock for PokéAPI

WireMock<span>.</span>Net is a library that let you create mocks for HTTP APIs. It creates a web server in the same process of our test and exposes an URL to be used by out application during the tests.

Using WireMock.Net and WebApplicationFactory we will have this scenario:

![Diagram of an integration test with WireMock.Net and WebApplicationFactory](https://blog.genezini.com/p/integration-tests-without-api-dependencies-with-asp.net-core-and-wiremock.net/images/Diagram2.png)

First, I install the `WireMock.Net` nuget package in my tests project.

#### Using Visual Studio Package Manager

```bash
Install-Package WireMock.Net
```

Or

#### Using .NET CLI

```bash
dotnet add package WireMock.Net
```

### Starting WireMock<span>.</span>Net server

To start the WireMock<span>.</span>Net server, I call the `Start` method of the `WireMockServer` class, and it returns an object with the server data.

```csharp
var WireMockSvr = WireMockServer.Start();
```

### Overriding out application configurations

With the server started, I override the `PokeApiBaseUrl` parameter, which holds the PokéAPI URL, in my application configurations using the method `WithWebHostBuilder` of the `WebApplicationFactory`:

```csharp
var HttpClient = _factory
    .WithWebHostBuilder(builder =>
    {
        builder.UseSetting("PokeApiBaseUrl", WireMockSvr.Url);
    })
    .CreateClient();
```

### Mocking the /pokemon endpoint

Then, I create the mock for the `/pokemon` endpoint receiving the parameter value `charmander`.

In the example below, I'm using the AutoFixture library to generate an object with random values, that will be returned by the mocked API.

> ℹ️ By using an object, I can compare the return of my application with this object, but it's also possible to configure the return based on an file with a JSON, with the `WithBodyFromFile` method.

Also, I set the headers that will be returned and the HTTP status of the response.

```csharp
Fixture fixture = new Fixture();

var ResponseObj = fixture.Create<PokemonInfo>();
var ResponseObjJson = JsonSerializer.Serialize(ResponseObj);

WireMockSvr
    .Given(Request.Create()
        .WithPath("/pokemon/charmander")
        .UsingGet())
    .RespondWith(Response.Create()
        .WithBody(ResponseObjJson)
        .WithHeader("Content-Type", "application/json")
        .WithStatusCode(HttpStatusCode.OK));
```

After that, my application inside the tests will be using the mocked version of the PokéAPI.

## Complete test code

```csharp
[Fact]
public async Task Get_Existing_Pokemon_Returns_200()
{
    //Arrange
    var WireMockSvr = WireMockServer.Start();

    var HttpClient = _factory
        .WithWebHostBuilder(builder =>
            {
                builder.UseSetting("PokeApiBaseUrl", WireMockSvr.Url);
            })
        .CreateClient();

    Fixture fixture = new Fixture();

    var ResponseObj = fixture.Create<PokemonInfo>();
    var ResponseObjJson = JsonSerializer.Serialize(ResponseObj);

    WireMockSvr
        .Given(Request.Create()
            .WithPath("/pokemon/charmander")
            .UsingGet())
        .RespondWith(Response.Create()
            .WithBody(ResponseObjJson)
            .WithHeader("Content-Type", "application/json")
            .WithStatusCode(HttpStatusCode.OK));

    //Act
    var HttpResponse = await HttpClient.GetAsync("/pokemoninfo/charmander");

    //Assert
    HttpResponse.StatusCode.Should().Be(HttpStatusCode.OK);

    var ResponseJson = await HttpResponse.Content.ReadAsStringAsync();
    var PokemonInfo = JsonSerializer.Deserialize<PokemonInfo>(ResponseJson);

    PokemonInfo.Should().BeEquivalentTo(ResponseObj);

    WireMockSvr.Stop();
}
```

## Example of an unsuccessfull API call scenario

Based on the contract of the API, we know that it return the status 404 (Not Found) when the parameter is not a valid Pokémon name, so I created a mock that returns this status for the parameter value `woodywoodpecker` and assert that my application response is correct for this scenario.

```csharp
[Fact]
public async Task Get_NotExisting_Pokemon_Returns_404()
{
    //Arrange
    var WireMockSvr = WireMockServer.Start();

    var Factory = _factory.WithWebHostBuilder(builder =>
    {
        builder.UseSetting("PokeApiBaseUrl", WireMockSvr.Url);
    });

    var HttpClient = Factory.CreateClient();

    Fixture fixture = new Fixture();

    WireMockSvr
        .Given(Request.Create()
            .WithPath("/pokemon/woodywoodpecker")
            .UsingGet())
        .RespondWith(Response.Create()
            .WithHeader("Content-Type", "application/json")
            .WithStatusCode(HttpStatusCode.NotFound));

    //Act
    var HttpResponse = await HttpClient
        .GetAsync("/pokemoninfo/woodywoodpecker");

    //Assert
    HttpResponse.StatusCode.Should().Be(HttpStatusCode.NotFound);

    WireMockSvr.Stop();
}
```

## Source code
https://github.com/dgenezini/PokemonInfoAPIWireMockTests

## Liked this post?

I post extra content in my personal blog. [Click here](https://blog.genezini.com/) to see.

## Follow me

- [On Feedly](https://feedly.com/i/subscription/feed/https://blog.genezini.com/index.xml)
- [RSS](https://blog.genezini.com/index.xml)
- [Linkedin](https://www.linkedin.com/in/danielgenezini/)
- [Twitter](https://twitter.com/GeneziniDaniel)

## References and links
- https://martinfowler.com/bliki/IntegrationTest.html
- https://khorikov.org/posts/2021-11-29-unmanaged-dependencies-explained/
- https://github.com/WireMock-Net/WireMock.Net
- https://github.com/reactiveui/refit
- https://github.com/AutoFixture/AutoFixture
- https://github.com/fluentassertions/fluentassertions