Testing systems that communicate with external systems

Lots of applications these days ,as part of their business logic, execute calls to external APIs that are developed by 3rd parties and are beyond our control. 
When writing Integration Tests for these systems we would like to validate that the communication patterns with the external APIs are correct.

One common problem is that 3rd party vendors usually provide their own client-side libraries that hide the complexities of working with the external service. Sometimes the protocols that are used are proprietary and hard to work with in tests. 
Sometimes it is impossible to configure the clients to communicate with anybody else but the external system it is supposed to talk to, which makes it difficult to “tap the wire” for testing purposes.

Here are 3 possible ways to test against such external systems:

Option 1: Use a Record-and-Playback Proxy Server
A record and playback proxy is a special case of a Fake Service that can run in 2 modes. When running in record mode it captures real communication with the external system and records the requests and the responses to disk. 
When running your system’s integration tests you can then start it up in a playback mode and have it respond with the recorded responses.
These can work well when the communication patterns are based on HTTP. 
Examples for such proxies are WireMock and Flashback

The problem with these tools is it can be difficult to match the requests to the correct response if the payload of the request contains random or timestamped data (common when using HTTPS). Flashback supposedly overcomes this problem with a flexible matching API.

When choosing this route it is important to periodically record new responses in case the external systems change their APIs so that the tests reflect the new responses.

Option 2: Configurable Adapter 
A Configure Adapter is an extension point for your system. The code of your system will use reflection to instantiate an object of the class of the adapter which can be read from a configuration file. 
In the test environment we can deploy the system with a fake adapter that passes the same contract test as the real adapter. The fake adapter can have a simplified implementation that doesn’t execute any network calls at all but instead stores data in a map in memory.
I prefer using reflection to using an “if(isTestMode){…}” clause because this way the tests don’t cover the branch that will execute in production.
It also introduces an extension point to the system that maintains the Open Closed Principle.

When using this pattern you still need to test the real adapter, preferably in a separate build since it executes external web calls and may fail the tests for the wrong reasons such as network failures, timeouts etc. 
Both the fake and real adapters should pass the same Contract Tests.
Some people object to this solution because the tests are running on a stack that is different from the actual production stack because of the fake adapter.

Option 3: Use a Simplicator
A Simplicator is an intermediary service in between your system and the external system. This service will expose an API and protocol that are very easy to work with and using terminology from your problem domain. The Simplicator will translate the simple protocol into the external system protocol.

When testing, a Simplicator is very easy to work with. We can always replace it with a regular Fake Service. Its also a good point to introduce caching in situations where cached responses are applicable, thus saving an external web call.

The downside of using a Simplicator is it adds an additional network hop and a possible point of failure. It also complicates your deployments if you’re not used to working with microservices.

The Simplicator should still be tested on its own usually against the external system using some sort of a test account or a test user. Just like in the case of a Configurable Adapter the tests for the Simplicator itself should run in a separate build due to the external web calls that will be executed.

For more about Simplicators read Nat Pryce’s blog post about the topic.

Hi I’m Sagy Rozman. 
I’ve spent the last 15 years writing code, leading agile software projects , speaking in meet-ups and conferences, running workshops and teaching developers about TDD, clean code and software craftsmanship. 
I currently work as a technical coach at Wix.com

You’re welcome to follow me on twitter