C# - A simple guide to setup Wiremock.Net for integration tests

Are you looking for a simple guide for setting up Wiremock.Net? Well I hope this can be helpful to you :) I did this yesterday as I wanted to use it for a hobby project. I am using the standard .Net Weatherforecast application as an example for this post. I am using xUnit, but you can use any testing framework you want.

You can see the structure of my project here:
Weather-Forecast-Test-Project

The standard WeatherForecastController looks something like the following:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
    
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

We can run a small test to see that this endpoint works:

var webApplicationFactory = new WebApplicationFactory<TestRestApplication.Startup>();
var client = webApplicationFactory.CreateClient();
var result = await client.GetAsync("WeatherForecast/");
Assert.NotNull(result);
Assert.True(result.IsSuccessStatusCode);
var responseContent = await result.Content.ReadAsStringAsync();
Assert.NotEmpty(responseContent);

In the above we use the WebApplicationFactory to start up our TestRestApplication for testing, this returns a HttpClient that we can use to interact with the Weatherforecast REST API. Due to the randomness of the API We just assert that the result is not empty. Next we will change the endpoint to call another endpoint and mock that using Wiremock.

Introducing Wiremock

In order to test this with Wiremock, we will edit our WeatherForecastController to call another endpoint which we will name WeatherForecastBackend, but otherwise have the same signature:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private HttpClient _backendHttpClient;
    
    public WeatherForecastController()
    {
        _backendHttpClient = new HttpClient();
    }
    
    [HttpGet]
    public async Task<IEnumerable<WeatherForecast>> Get()
    {
        var result = await _backendHttpClient.GetAsync("http://localhost:58116/weatherforecastbackend");
        return JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(await result.Content.ReadAsStringAsync());
    }
}

The above example now calls "http://localhost:58116/weatherforecastbackend" which we will mock later so it returns the actual Weatherforecast. Other than this the signature of the endpoint is not changed. In the example I have hardcoded the URL for simplicity of this post. For professional use, you can inject the hostname/port using the appsettings.json, so that you can point it to the dummy endpoint in your test, but the real endpoint in your Rest API project.

Below we are setting up Wiremock to handle requests on "http://localhost:58116/weatherforecastbackend":

var Summaries = new[] {
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"

var rng = new Random();
var weatherForecastBackendStubResponse = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
    Date = DateTime.Now.AddDays(index),
    TemperatureC = rng.Next(-20, 55),
    Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToList(

var stubResponseSerialized = JsonConvert.SerializeObject(weatherForecastBackendStubResponse

var server = WireMockServer.Start(58116);
server
    .Given(
        Request.Create()
            .WithPath("/weatherforecastbackend")
            .UsingGet()
    )
    .RespondWith(
        Response.Create()
            .WithStatusCode(200)
            .WithBody(stubResponseSerialized)
    );

We have taken the original logic for creating the Weatherforecast and moved it to our tests - nothing amazing there. Then we start our Wiremock server using WireMockServer.Start(58116) and start configuring it. In the "Given" part we setup our Request matcher - Request.Create() - to match requests on the path "/weatherforecastbackend" using the HTTP GET Verb. In the "RespondWith" method we configure the response to return a status code 200 and the body to contain the serialized Weatherforecast as JSON.

We can then use the same test logic as before to verify that we are getting the correct response when running the test:

var webApplicationFactory = new WebApplicationFactory<TestRestApplication.Startup>();
var client = webApplicationFactory.CreateClient();

var result = await client.GetAsync("WeatherForecast/");
Assert.NotNull(result);
Assert.True(result.IsSuccessStatusCode);

var responseContent = await result.Content.ReadAsStringAsync();
Assert.NotEmpty(responseContent);

var responseAsWeatherForecast = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(responseContent);
Assert.Equal(stubResponseSerialized.ToLowerInvariant(), responseContent.ToLowerInvariant());

and we can see that we get the response from wiremock when we debug:

Weatherforecast-wiremock-response

That is it!

I hope you found this post on how to use Wiremock helpful, let me know in the comments down below if I should put more details anywhere in the post :)

Happy testing!