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 library.
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.
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.
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.
The controller is simple and use the Refit library to abstract the PokéAPI call and then, returns the data.
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
WebApplicationFactoryin your tests. If you’re using top-level statements in your application, you can use a controller class. For example,
WireMock.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:
First, I install the
WireMock.Net nuget package in my tests project.
dotnet add package WireMock.Net
To start the WireMock.Net server, I call the
Start method of the
WireMockServer class, and it returns an object with the server data.
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
Then, I create the mock for the
/pokemon endpoint receiving the parameter value
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
Also, I set the headers that will be returned and the HTTP status of the response.
After that, my application inside the tests will be using the mocked version of the PokéAPI.
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.
In this post I explain how to troubleshoot problems with WireMock.Net and talk about some common problems that I see in my daily work.