Faking third party web services

I’ve worked on a number of projects that relied on third party web services or API’s.  Most of these had a test service but didn’t provide a way to return a predetermined response.

This left two choices when testing our software; call the test service or create a fake service of our own

Third party test services

Usually the purpose of a test service is to ensure that your production systems will work with their production systems.  So it is used for testing the integration of two systems.

This usually means the only difference is the data is not real or is a sub-set of the live data.  Using it still requires calls across service boundaries (HTTP), expensive computation and storage (like databases).

This creates a number of issues when executing an automated test suite for your software;

  • Calls across services boundaries are expensive, resulting in slow tests and slow feedback
  • Tests will be brittle because the data can change, leading to different results over time
  • You may not have access even to the test service in the environment you are running your tests

Faking services

The solution is invariably to create a fake service that can be configured to return a specific response.

I’ve done this a few times and without exception the solution has become a maintenance burden. Some  of the problems I’ve experienced are below;

  • Fake is not re-usable across projects
  • Duplication of fakes across teams
  • Different fakes for different third party services

This leads to a lot of duplication of effort and lost time.

Proxy servers

After realising this could be solved with a proxy server I created Boomerang to make this easier.  This enables developers to set predetermined responses for HTTP requests.

For example, I can specify a json object should be returned from a GET for a specific relative address;

var dictionary = new Dictionary<string, string>() { { "content-type", "application/json" } };
Boomerang.Server(5100).Get("/api/products").Returns(products.SerialiseToJsonString(), 200, dictionary);

This creates a proxy server on port 5100 and specifies the response to a HTTP GET request to the relative uri /api/products should be a list of Products formatted as json.

I created an extension method to help with the json serialisation;

public static string SerialiseToJsonString(this object target)
        {
            string str;

            var dataContractJsonSerializer = new DataContractJsonSerializer(target.GetType());

            using (var mem = new MemoryStream())
            {
                dataContractJsonSerializer.WriteObject(mem, target);
                mem.Flush();
                mem.Position = 0;
                str = Encoding.Default.GetString(mem.ToArray());
                Console.WriteLine(str);
            }

            return str;
        }

Conclusion

GET, POST, PUT and delete are supported and the base address is ignored.  If Boomerang receives a request it hasn’t got a response for it will return an error response.

I hope this makes testing with third party services a bit easier!