Final Remarks on Testing External Services

Learn about which approach is best suitable for testing third-party HTTP services and how to test Non-HTTP Services.

Which approach is best for testing external services?

We saw three possible approaches to testing third-party HTTP services:

  • Making real requests
  • Running a test server that mocks the service
  • Recording real requests and replaying them

As is often the case in our industry, there’s no definitive best approach among these. Each one fits some use cases better.

Test server

Building a test server is the way to go if we want tight control over how the third-party API should behave. This lets us test different responses from the API and gives us flexibility. However, the trade-off is having to build the test server and keep it up to date with the real API.

ExVCR

If we want to mimic the API perfectly and use one of the supported HTTP clients, then ExVCR is a good alternative. The trade-off is that we have to keep cassettes up to date, but that’s something that we can only avoid by going with the real requests approach anyway.

Real requests

If we can get away with making real requests to a service, then it’s often a good idea to do that. Many HTTP services provide sandbox environments specifically for testing or are idempotent, meaning that we can make requests without affecting the state of the service. Even in these cases, though, we might want to avoid the real requests approach if we don’t want to rely on an Internet connection in our tests.

Tip: Relying on an Internet connection can also cause all sorts of weird problems if the connection is unstable. We’re fans of a workaround that gives us an excellent way to deal with this. We tag our tests that use the Internet as @tag :requires_internet. This way, if we don’t have a connection available, we can run mix test --exclude requires_internet and still run all the tests that don’t require the connection.

Testing non-HTTP services

Most of the concepts we discussed apply to non-HTTP services as well. For example, if we’re talking with a service that exposes a binary protocol, we can build an interface (with a behavior) that specifies how to interact with the service. Then we can use dependency doubles to test components that talk to the service through the interface.

However, testing the actual interaction with a service that doesn’t expose an HTTP interface is more complex because fewer tools are available. If we want to build a test server, we’ll often have to implement that ourselves on lower-level protocols like TCP. If we want cassettes, we’ll have to implement all of the infrastructure needed for them ourselves because there isn’t an ExVCR counterpart for protocols other than HTTP.

Get hands-on with 1200+ tech skills courses.