Using WireMock to Empower Integration Testing in Distributed Systems

Larry GasikLarry Gasik
4 min read

I’ve had testing on my mind lately—specifically, how our team approaches automated unit tests, integration tests, and broader validations like smoke testing. What should we be asserting? What behaviors actually matter? These thoughts were front and center when I listened to Henry Suryawirawan’s Tech Lead Journal podcast, episode 210, featuring Tom Akehurst, the creator of WireMock.

If you haven’t heard of it, WireMock isn’t just another mocking tool for faking out classes or interfaces in unit tests. It’s much more powerful in the context of integration testing. Rather than mocking a method in your own codebase, WireMock runs as an actual HTTP server, allowing you to simulate entire RESTful APIs. You can define how an endpoint behaves—from returning expected payloads to simulating latency, timeouts, and various HTTP error codes like 500, 404, or even connection failures.

This is a game-changer when working with distributed systems—where failure is not just a possibility, it's an eventuality.

Take the following example:

Something like this call pattern is common: a front-end Angular application calls an API Gateway (written in .NET), which then routes the request to a specific microservice. That service, in turn, calls a Java-based payment gateway, which finally sends a request to a third-party payment processor.

Simple in theory but in practice, it’s a house of cards. If anything downstream fails—especially during development or testing— delays and errors propagate backward. Maybe the payment processor returns a 500, or the payment gateway times out. As a result, your microservice fails, the API Gateway propagates the error, and your front-end test suite lights up in red.

Or what if the API Gateway isn’t done being developed? How do I verify the microservice’s logic if the payment gateway is unstable? How can we test independently without needing every downstream component to be built or available? What if the test environment is limited or even unavailable?

This is where WireMock comes into play.

Instead of setting up test data or configuring every downstream service in coordination, you use WireMock to simulate those services entirely. Need a 504 Gateway Timeout from the payment gateway? Easy. Want the payment processor to return an empty body with a 403? Done. You’re no longer blocked by other teams or waiting for environments to be stable.

WireMock empowers teams to test edge cases, failure conditions, and success paths without coupling themselves to actual implementations or shared staging environments. It works at the HTTP layer, decoupled from your application logic, giving you complete control over what the rest of your system sees when it makes a network call.

A Practical Example

In the next section, I’ll walk through how you can use WireMock to simulate calls to dependent services. I fired up a simple in-memory HTTP server and configured examples of a GET, POST, and PUT. I also leveraged those calls to return success, a timeout, and an internal server error (those don’t happen in real life, right? RIGHT?)

Here’s what we’re going to make happen for our example:

I shared the source code on github.com/LarryGasik, but I’ll drop it here too:

using WireMock.RequestBuilders;
using WireMock.ResponseBuilders;
using WireMock.Server;

Console.WriteLine("Let's do Hello world");
var server = WireMockServer.Start(port: 5001); // http://localhost:5001
Console.WriteLine("WireMock running at {0}", server.Urls[0]);

server
    .Given(
        Request.Create()
            .WithPath("/api/hello")
            .UsingGet()
    )
    .RespondWith(
        Response.Create()
            .WithStatusCode(200)
            .WithHeader("Content-Type", "application/json")
            .WithBody("{ \"message\": \"Diesel wants to be fed\" }")
    );

server
    .Given(
        Request.Create()
            .WithPath("/api/ThrowError")
            .UsingPost()
    )
    .RespondWith(
        Response.Create()
            .WithStatusCode(500)
            .WithHeader("Content-Type", "application/json")
            .WithBody("{ \"error\": \"Something went wrong on the server.\" }")
    );
server
    .Given(
        Request.Create()
            .WithPath("/api/TakeYourTime")
            .UsingPut()
    )
    .RespondWith(
        Response.Create()
            .WithStatusCode(504)
            .WithDelay(TimeSpan.FromSeconds(3)) 
            .WithHeader("Content-Type", "application/json")
            .WithBody("{ \"error\": \"Gateway timeout. Server is taking too long to respond.\" }")
    );

Console.WriteLine("Execute a get on http://localhost:5001/api/hello");
Console.WriteLine("Execute a post on http://localhost:5001/api/ThrowError");
Console.WriteLine("Execute a put on http://localhost:5001/api/TakeYourTime");
Console.ReadKey();

server.Stop();

And here’s my Postman call that shows the result. Notice how, in the gateway timeout, I introduced a 3-second delay. This can be incredibly helpful for simulating a backend that is slow or unresponsive.

This approach empowers the development team to intercept traffic at a local level. Any response can be simulated, allowing you to test the happy path and your edge cases. You don’t need to spin up an entire cluster or have a full test environment just for your change.

This is an important part of removing coupling from your development process. Use it for your integration tests, edge cases, third-party testing—or even demos!

If you want your services to be independently deployable, they need to be independently changeable. If they need to be independently changeable, they must be individually testable. And if they’re individually testable, they should have only one reason to change—and this is the Single Responsibility Principle.

We enable this using the Interface Segregation Principle, delegating responsibilities downstream. It all ties back to SOLID.

Edge cases, efficient testing, avoiding surprises, bad behaviors—WireMock is a powerful tool for any sort of distributed solution. And in 2025, that’s pretty much all of them.

10
Subscribe to my newsletter

Read articles from Larry Gasik directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Larry Gasik
Larry Gasik