Fake it as you make it: why fake services are awesome for developers

Jan 25, 2016 · 6 min read

This blog post comes from Shea Daniels, a developer at Dwolla. When Shea isn’t busy building awesome new things, you can usually find him out for a run.

It’s often said in life that we “stand on the shoulders of giants.” This rings especially true now that we’re in an era of abundant open source software and SaaS providers.

Building software by composing services is extremely powerful, but it can still be a rocky road. Several factors can make it difficult to write and test your code:

  • Complex scenarios may not be easy to test with real data
  • Running elaborate business logic may consume resources
  • Sandbox environments may not exist for 3rd party APIs

Just fake it

You can see this in everyday life. Whenever the real thing is too expensive or impractical, we sub it out with something fake as a stand in — think movie props or mannequins for tailors. This is also a fairly common engineering practice; my favorite examples are the boilerplate capsules used to evaluate rockets and other space hardware.

In the software world, if you practice TDD you should be familiar with the use of test doubles (mocks, fakes, and stubs) for dependencies in your unit testing code. Used instead of the real implementations of objects, fake dependencies isolate the code under test by providing predictable results given certain input. This isolation is useful for tracking down issues and fully exercising your code without complicated setup.

The same concept can be applied when developing an integration with a third party service. By building a fake copy of the web service, you gain the same advantages of isolation and repeatability as you test your application. This is especially useful if the service you’re depending on is being developed in tandem and has yet to be fully implemented.

There are some existing tools for quickly standing up your own fake services, such as Nock and Frock. But with Node.js and a few NPM packages, it’s easy enough to build your own from scratch.

In this post we’ll include:

  • An actual example
  • How to get started
  • Possible scenarios
  • Some of the downsides

A real example

Getting started

If you haven’t used Node or express before, there are a ton of great tutorials, or you can read through the Nodlee source code to get a feel for it. The readme has a lot of great info and the code entry point is app.js.


For a simple example, here’s the Nodlee health check endpoint response: health.js

module.exports = function (req, res) {
res.json({ healthy: true });

These responses can be as simple or as complicated as needed.

Complex scenarios

The first step to making this easier was to consolidate all of the possibilities that determined a particular scenario into a single list of options in the code: scenario.js

module.exports = function Scenario() {

this.contentServiceId = 0;
this.isMfa = true;
this.mfaTimeout = false;
this.mfaPass = true;
this.mfaTypes = ['q'];
this.refreshesSet = 1;
this.refreshesLeft = 1;
this.errorType = 0;
this.accounts = [
routingNumber: '222222226',
accountNumber: '5031123001',
accountType: 'CHECKING',
accountHolder: 'John Wayne',
accountName: 'Your Account #1',
balance: '1000'

This object can then be checked in all of the service endpoints in order to determine the appropriate response. With this in place, developers could set up the flow to behave however they wanted just by editing this single file.

Sentinel values on steroids

What we need now is a service with a memory longer than a single web request and a way for automated tests to trigger whatever scenario is needed. This is where the minimist and node-cache NPM packages come into play.

With minimist, we are able to take certain inputs in a web request and treat them as if they were command line interface options. Those options can then be translated into order to set the properties of the Scenario object we’ve just discussed:

var scenarioData = optionsParser.parse(req.body.someInput)


exports.parse = function(options) {

var data = new Scenario();

if (options.indexOf("-") < 0) {
return data;

var args = parseArgs(options.split(' '));

if (args['nomfa'])
data.isMfa = false;


return data;

Now that we have the options set for the scenario we want, we use node-cache to persist it across web requests: scenarioManager.js

var cache = new NodeCache({ stdTTL: 900, checkperiod: 300 });

exports.set = function(...) {


cache.set(userSessionToken, scenarioData);
return scenarioData;

Now we can use the cache to access the scenario that’s currently being tested at any point we need to build a response: getMfaResponse.js:

module.exports = function(req, res) {

scenarioManager.get(req.body.userSessionToken, function(scenarioData) {

if (!scenarioData.mfaTypes) {
} else if (scenarioData.mfaTypes.length < 1) {
} else {

The downsides

  • Are you sure you understand the real service well enough to build a fake version of it?
  • Watch for edge cases where you may not be duplicating the behavior of the real service
  • If you do find edge cases, be sure to cover them with appropriate tests; manual testing with your fake service is not a replacement for good test coverage with unit/integration tests
  • Plan for regular maintenance of your fake to keep up with any changes in the interface or behavior of the API you depend on
  • Using a fake does not relieve you from the task of running your code against the genuine article

The last bullet point is important since there’s a large difference between “should work” and “actually works.” At some point in your workflow you’ll need to test the full production stack!


Here at Dwolla we’re committed to making developers’ lives easier by providing a great API for moving money with ACH transfers.

Originally published at blog.dwolla.com on January 25, 2016.


Power your app with a modern payment platform.


We enable innovators to program their payments with scalable and reliable technology.


Written by


Power your app with programmable payments infrastructure.


We enable innovators to program their payments with scalable and reliable technology.