Regression Testing NodeJS Services with Restify and Mocha

Here at Flurry we are big proponents of unit testing and TDD (Test-driven Development) - we believe it makes for tighter code that is less prone to behaving in unexpected ways.  We also believe in extensive Regression Testing - making sure the changes and code we add don’t break existing functionality.

Recently we have begun moving parts of the Flurry backend over to a new set of services running on NodeJs.  NodeJS is a fast, flexible application framework that is especially suited to developing RESTful API services.

Restify

To help us build these new backend components we’re using the NodeJS “Restify” framework.  Restify provides an extensive amount of low-level functionality to help you correctly implement RESTful services - much in the same way the “Express” NodeJS module helps you rapidly develop web-based applications - for those of you familiar with Express, you’d feel right at home in Restify.  We’ve found Restify to be a fantastic framework for development - easy to use, understand and implement.

Mocha

To facilitate unit testing, we’re using the Mocha Javascript unit testing framework for everything we do and have found it to be flexible and easy to use.  Mocha makes it really easy to write unit tests for your NodeJS code - so easy in fact, we decided we wanted to use Mocha for our regression testing.

After some trial and error, we have settled on a fairly simple setup, which we have found works well and is easy to implement.  The following steps outline the process, and for this small tutorial we’ll build the requisite “Hello World” API that simple returns “Hello World” when called.

Before we get started, we first want to make sure that both Restify and Mocha are installed for use in our new Node project:

Once those are installed, we’re ready to create our sample “Hello World” API service, as well as setup the Mocha regression test cases.

Here’s the contents of the app.js file that we will be using for testing:

You can see that unlike other app.js examples you may have seen, this one is very small and simply makes a function call to StartServer() which has been exported from the start_server.js file.  This function simply starts the server - we’ll cover that below.

Start up the NodeJS service in Mocha

Before we can do any regression testing against our “Hello World” service, we must first start up the Hello World service.  To do this, we are going to create a special “before” Mocha hook - this will run before any of the other regression test files are run by Mocha, and will allow us to start the service so it can be tested.

Within your directory, create a sub directory called “test”.  All of our regression test and unit test files are going to be located inside.  Create a new file called “01-start-server.js” with the following contents:

This file will be picked up as the first file in the directory (that's why we started the filename with 01), and the before() function will be executed, which in turn requires and runs our StartServer() function.   The StartServer() function is defined in the start_server.js file:

It's purpose is to actually initialize the Restify listeners and start the service.

Create a Mocha regression test

Now that we have a way to automatically start the service before we need to test it, we can go about the business of writing our regression test cases.  Since our Hello World service is so simple, we’re just going to have one test - we’re going to test to be sure our call to the /hello service returns an HTTP response code of “200”, indicating our request was “OK”:

Initializing an HTTP Client

At the very top of our file that contains the test cases for our Hello World service you can see we are using a feature of Restify - the Restify JSON Client.  The JSON Client is a small wrapper around NodeJS’s http module that makes it easy to call URL based web services that return their content in JSON format.  The JSON client will automatically JSON.parse the response body and make it available for your use (as the “data” parameter in our callback function).

Once we’ve created our client, we can then use the client to make a GET call to our /hello service URL.  If we encounter an error connecting to the service, our “err” parameter will contain the error.  The “data” parameter will contain the data returned from the call, so we will want to check that to be sure it contains the data we requested. 

Running the Regression Test

Now that we have our test in place, the next step is to actually run it, which is as easy as typing "mocha" in your project directory:

Mocha will first run the "01-start-server.js" file in the test directory - this starts our service.  Next, it will move on to the service_hello_tests.js file and run our solitary regression test.  If the service responds as we have outlined in our test, the test will be marked as passed by Mocha.

Using this simple setup we can add as many additional tests as needed - either extending our "hello" service, or writing additional test cases for new services.

Using Mocha for both unit testing and regression testing allows us to save time by only having to deal with one testing framework - Mocha is flexible enough to make running unit tests in more complex scenarios fairly straight forward and easy to do.  Now if only it could write your unit tests for you :)

3 responses
Hey, Just wondered if you had tried to mock out your restify API using nock or some other mocking framework. I couldn't get my restify json client to hit the mocked api routes.
Chris - thanks for the question. I haven't actually tried doing that - I'm not sure if Restify is going to follow a mocked route (just based on how I've used it). You might need to build stubs for the Restify routes and add your mock responses there - not ideal, but it gets you started with a a test you can build on.
It's not Mocha or Restify, but have you seen APIEasy [1]? It's a nice way of quickly writing particularly expressive tests for rest apis. Could take many of it's ideas to use on top of mocha.

1. https://github.com/flatiron/api-easy