Building high quality end to end acceptance tests suites is hard, and creating API stubs (aka mock servers) can be surprisingly time consuming. WireMock.net can help speed this up.
E2E testing is hard
End to end testing is hard for many reasons, but I think one of the most common is that the developers under estimate how much time to allow for it and then rush the job. Most E2E test harnesess I have worked on, (including several I wrote myself!) fail intermittently because of race conditions, are littered with sleep statements to make them more reliable, and break when some external dependecy is not available. One of the best ways to mitigate this is to create test stubs for all external dependencies as part of you test harness.
Stubbing all those HTTP APIs
However, stubbing all dependencies requires more effort than you might expect now that most modern apps contain and integrate with more APIs than ever – application APIs, external data sources, login providers, CDNs, cloud payment services etc. Setting up a separate deployable http endpoint stub for each takes time, especially as typically each one has it’s own special behaviours, encodings, content types, response codes and authorization methods you have to stub around or provide canned responses for.
Sometimes the API you need to integrate with is not built yet, or it is not accesible in your development environment and all you have is the dreaded API definition document (or a swagger definition if you are lucky!).
Stubs vs Mocks - What’s the difference?
StackOverflow has this covered!
Problem solved, just twenty bucks per person per month
There are lots of tools and services that aim to help in these sorts of scenarios, Postman, Apiary and Mockable to name but a few, however in my experience they are either too simple (cannot cope with a dynamically generated response say) or too complicated and slow to configure. Another gotcha with the paid-for services is that they usually hold your test data outside of your source control system meaning tests break in two weeks time because someone else changed the data wthout considering that test.
Trying out WireMock.net to create api stubs
I recently discovered the open source library WireMock.net and so far I think it sits neatly in the sweetspot between productivity and flexibility. It dramatically reduced time spent stub building on a project and was comprehensive enought to cope with some non-trivial testing requirements. It supports .net full framework and dotnet core and is available on nuget.
One other big advantage of it being an OSS library is that it is exstensible, and indeed when I needed HTTP PATCH support in WireMock.Net, or I found a bug, a quick fork and pull request later and it was fixed and merged into the released product in a few hours. Hat tip to StefH for that.
Here is a quick demo of how you can get started using WireMock.net.
Add a new .net core 2 console app to host your api stubs to your existing app solution
dotnet new console -f netcoreapp2.0 -n ApiStub
And then install WireMock.net from nuget
dotnet add ApiStub package wiremock.net
Create a stub http server in Program.cs
using System;
using WireMock.Server;
using WireMock.Settings;
namespace ApiStub
{
class Program
{
static void Main(string[] args)
{
var stub = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://+:5001" },
StartAdminInterface = true
});
Console.WriteLine("Press any key to stop the server");
Console.ReadLine();
stub.Stop();
}
}
}
Yup, thats all that is needed to setup the simplest http server. Start the server to check it works as expected:
dotnet restore ApiStub
dotnet run ApiStub
Now browse to http://localhost:5001
and you should get a 404 Not Found
with response No matching mapping found
. This means our stub is up and running. Stop the server and then we will use the c# fluent syntax to add a non-trivial stubbed behaviour:
stub.Given(
Request.Create()
.WithPath("/oauth2/access")
.UsingPost()
.WithBody("grant_type=password;username=u;password=p"))
.RespondWith(Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(new { access_token = "AT", refresh_token = "RT" }));
Now if I open a http utility like Postman and send a POST to http://localhost:5001/oauth2/access with the body specified I recieve a nice stubbed json response.
More sample app code can be found at https://github.com/WireMock-Net/WireMock.Net/blob/master/examples/WireMock.Net.ConsoleApplication/MainApp.cs
JSON configuration files
WireMock also supports specifying stubs using JSON files called static mappings. First turn on the mappings feature:
var stub = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://+:5001" },
AdminInterface = true,
ReadStaticMapings = true
});
And then add a JSON file in a folder below the program.cs
file that describes the stubs behaviour __admin\mappings\MyNewStubResponse.json
{
"Request": {
"Url": {
"Matchers": [
{
"Name": "WildcardMatcher",
"Pattern": "/search?q=*"
}
]
},
"Methods": [ "get" ]
},
"Response": {
"BodyAsJson": {
"searchResults": [
{ "link":"http://example.com" }
]
},
"Headers": { "Content-Type": "application/json" }
}
}
The file should be self explanatory and most technical team members could learn to write the json files as they are very readable. WireMock support all kinds of more complex stub behaviours, check out the well written docs for more information.
Assert your success
As long as your ApiStub server is running, it will keep track of all the requests and responses made. Use stub.LogEntries
to get an Enumerable of all the requests made. In addition to the c# library your mock server has a fully fledged administration http API all of its own. This allows you to remotely interrogate and configure the stub server.
For example GET http://localhost:5001/__admin/requests
lists all the API calls you have made to it, including which mapping was used to generate the response (sometimes useful in debugging the stub mappings), and what response was sent. And GET http://localhost:5001/__admin/mappings
returns all the mappings that have been setup in an easy to understand json format just like the static mappings.
Using this admin API allows you to start a stub, run the app pointing at the stub and then assert that the correct data and requests were made against the stub with the admin API. Your application thinks it is consuming a real external service, and your test framework can guarantee the exactly the correct number and types of HTTP requests were made.
Locally the test harness can be in the same process as the system under test and the stub, but under a continous integration environment you may want to test a real deployed instance of your system. This may mean the stub is running in a different process to the tests. If thats the case then there is a lovely typed c# client library baked into the library that makes calling the admin API from c# easy. Under the hood is uses RestEase.
To get the log of requests from a remote stub is just three lines of code:
using WireMock.Client;
using RestEase;
...
var stubUrl = "http://localhost:5001";
var stubApiClient = RestClient.For<IFluentMockServerAdmin>(stubUrl);
var stubLogEntries = await stubApiClient.GetRequestsAsync();
The Admin API is very comprehensive, see the docs at https://github.com/WireMock-Net/WireMock.Net/wiki/Admin-API-Reference
Quickly generate stub data
WireMock also makes it really easy to generate the static mapping json files based on real API calls using the Proxy-And-Record feature. This works by directing real API requests to the external service you are intending to stub through a temporary recording proxy hosted locally. The proxy saves every request into a seperate json files such as __admin/mapping/SomeGuid.json
, ready to be loaded back as static mappings by your stub server.
Adding a recording proxy into the same apiStub assembly is easy:
var apiRecordingProxy = FluentMockServer.Start(new FluentMockServerSettings
{
Urls = new[] { "http://+:5002" }, //different port
ProxyAndRecordSettings = new ProxyAndRecordSettings(){
Url = "http://example.com",
SaveMapping = true
}
});
Now whenever I send a GET to http://localhost:5002/api/orders the proxy sends a GET request to http://example.com/api/orders, returns the response, and generates a new static mapping json file on disk ready. This file can then be loaded by the stub server next time it runs.
Typical stubbing workflow
Combining the proxy recording, HTTP API stubbing and the admin API gives you a very productive development workflow to generate new test data based on real API calls and use them in end to end tests:
- Add a quick recording proxy to the stub
- Send some real API calls to the service via the recording proxy using the app I am building or postman.
- Inspect all the static mapping json files generated and rename them, tweak the behaviour to make them more generic, and delete any duplicates.
- Reload the api stub and check the stub now has all the newly learnt canned responses
- use the stub in my tests and assert against the admin API.
- check the static mappings into source code when it passes.
Overall the features in wiremock.net make api stub generation and end to end testing less time consuming and more reliable. Why not use it in your next project? Or what else do you use to mock servers - answers in the comments.