Jim Kubicek

Octo-Impressive

Unit Testing Parse Cloud Code

Like many people, I was thrilled when Parse announced their cloud code product. I’ve just started a little iOS project that required both persistent cloud storage and pulling data from a 3rd party API. Since the API had a great JavaScript library, but no built-in Obj-C support, moving the code onto the server had some big benefits: greatly simplified networking in iOS, allowed me to reuse the 3rd party library as is, and decreases my turnaround time should I need to modify this code in the future.

Now, I’m usually not a strict test driven developer, but these cloud code modules are a different story; the code is running on a server and accessing a 3rd party API. In this situation, quick build/test/debug cycles are impossible and testing is the only way go.

Here’s how I set up my testing environment. Please keep in mind that this is the first time I’ve used Node.js, first time I’ve written unit tests for JavaScript and the first real JS project I’ve worked on. In fact, before this, the only JS code I’d written was hackly little Safari extensions, so this is a whole new world for me. I’m writing this for someone with experience similar to mine; if you are experienced with Node, feel free to skip ahead.

Setting up the test environment

I assume you’ve already got Node and npm installed. If you don’t, they both can be installed via Homebrew.

I used Mocha.js for the testing framework and Expect.js for assertions. Mocha supports any assertion framework you can throw at it. Expect seems to work well and doesn’t generate Lint warnings like Should.js. Run the following commands from your project directory.

$ npm install mocha
$ npm install expect.js

These commands install the mocha and expect frameworks in the local node_modules directory. This greatly simplifies your environment. Code can be shared between collaborators without worrying about what framework version each dev has installed.

At this point, your Parse directory should look like this:

cloud /
  main.js
config /
  global.json
node_modules /
  .bin /
  mocha /
  expect /

Creating Cloud Code Modules

We’re all set to test, but first we need something to test. We’re going to add some code that just returns a helpful message. Modify main.js to look like so:

1
2
3
4
5
var message = require('cloud/message.js');

Parse.Cloud.define("get_message", function (request, response) {
  message.getMessage(request, response);
});

What I’ve done is load each Cloud Code function from a separate module, this worked well for me because each function is independent of all other functions, but YMMV. Let’s setup some code to test. First, create a file named message.js in your cloud directory. Now modify it to look like so.

1
2
3
exports.getMessage = function (request, response) {
  response.success("Good job, buddy");
};

A bit about how Node.js loads modules, since this was all new to me. When each module is loaded, there is an object created called exports that is available within that module. Any function attached to that object will be available externally when your module is loaded. So in this example, our message module creates one function called getMessage. When we call var message = require('cloud/message.js'); the object returned from the require() function is that exports object.

Creating Tests

Now let’s create some tests. First, the default directory for Mocha tests is test, so let’s put our test there. Create the test directory and put a file in there named, “messageTests.js”. Modify it to look like this:

1
2
3
4
5
6
7
8
9
10
var message = require('../cloud/message.js');
var expect = require("expect.js");

describe('Message', function () {
  describe('response', function () {
      it('should return the correct message', function () {
          expect().fail("No tests yet");
      });
  });
});

First we import our message and expect modules. The describe() function is used to define the scope for associated tests. The it() function defines a Mocha test. Let’s run our test.

$ node_modules/.bin/mocha 

Notice that the error message says, “Message response should return the correct message:”, so structure your describe and it messages to make that message nice and readable. Let’s replace our failing test with an actual tests.

1
2
3
4
5
6
7
8
it('should return the correct message', function (done) {
  message.getMessage({}, {
      success : function (message) {
          done();
          expect(message).to.be.eql("Good job, buddy");
      }
  });
});

There’s a few things to notice here. First, the done() function is an optional parameter to the describe() and it() methods. Any tests within will not complete successfully until the done() function is called, so you can use it to test callbacks and ensure that they were called. Second, notice the format of the expect() function. You can read the documentation for more details, but in general, the tests always follow this form, beginning with an expect() function and ending with a function.

Run the tests again and success! All our tests pass. All in all, it took me less than a day to try out different testing and exception modules, settle on Mocha and Expect, then write enough tests to nearly fully cover the Cloud Code I had written. Coming from Objective-C, the power and flexibility of JavaScript amazes me. Writing these tests was almost a joy.

Comments