Node.js Automated Testing: A Quick Intro to Writing and Running Tests
Node.js does not come with a formal testing suite (though there are several available). However, it comes with the necessary tools for writing simple and effective automated tests. This is a quick explanation of how to write simple tests for Node.js code. We cover the directory structure for testing, the
assert
class of Node.js, and automating the process with make
and a Makefile
.
By the end of this short blog, you should be able to quickly and easily write automated tests for your Node.js packages. <!--break-->
1. A home for tests
First, your code should have a directory for storing your tests:
$ mkdir test
We will place all of our tests inside of this directory.
2. Some code to test
Let's say we want to develop a simple Hello World
class. In Node, classes are typically stored in lib/
, so we'll create lib/hello.js
.
module.exports = Hello;
function Hello() {
}
Hello.prototype.sayHello = function (name) {
if (name == undefined) {
name = 'world';
}
return "Hello " + name;
}
This simple module creates a prototype object called Hello
which has one function: sayHello()
. The sayHello()
function has an optional name
argument. If name
is supplied, this will print "Hello NAME". Otherwise it will print "Hello world".
Now we are ready to write a simple test to verify that Hello
works as expected.
3. A simple test
We will use Node.js's built-in assert
library to test Hello
. And we will create a test called test/test-hello.js
. Not only to we make sure to put the test in the test/
folder, but we prepend test-
to the name. This will assist us in making the running of tests easier.
Here is what test/test-hello.js
looks like:
var assert = require('assert');
var Hello = require('../lib/hello');
// First, create a new Hello object:
var myHello = new Hello();
// Now test that it generates 'Hello world' when no params are given:
assert.equal(myHello.sayHello(), "Hello world");
// Test that it says "Hello NAME" when we pass in "NAME"
assert.equal(myHello.sayHello("Matt"), "Hello Matt");
That is all there is to creating a simple automated test of the new code. As you can see, there is nothing special about this code. There is no big unit testing framework to learn. That makes writing the tests easy (though we are missing some bells and whistles that come with unit testing or behavioral testing packages).
We can run the test like any other Node.js script: node test/test-hello.js
. If the tests pass, no output will be generated. If anything fails, Node will print a stack trace showing us what went wrong and where.
This is one test for one piece of functionality. But as your application grows, you should find yourself writing separate tests (in separate files) for each unit of functionality (each prototype or file or module). It would get tedious to run each test by hand. So we will write a build script to automate the running of tests.
4. A Makefile to Run Tests
How can we best run all of our tests? We can use a build script.
Typically, Node.js modules use some version of make
(a UNIX build tool) to handle package tasks. make
looks for a special configuration file called, appropriately, Makefile
.
In our case, we need to write a simple Makefile
that provides a testing target. The Makefile
should be in the top level of your project.
We will build a Makefile
with a single target for running all of the automated tests in our test/
directory:
SHELL := /bin/bash
test:
@find test/test-*.js | xargs -n 1 -t node
.PHONY: test
The first line simple tells Make that we want to use the bash
shell.
From there, we define targets for make. A target is a named command that we can ask make to run for us. Our target is test
. To execute this target from the command line, we can type make test
.
Make will then run one or more shell commands for our target. In the example above, it runs a basic UNIX command which finds all of the files in test/*
that match the pattern test-*.js
. Since our test above matches that pattern, find will pass each matched file to xargs
, which will then in turn execute each file with node
.
In other words, that single-line find
/xargs
command does this:
- Find all files that match
test/test-*.js
(find
) - Then with each file, build the command
node FILE
- And then run this
node FILE
command
On the final line of the Makefile
, you'll notice .PHONY: test
. In a nutshell, this special target tells make
which targets can be run. (A full explanation is available in the Make documentation). Most of the time, in Node.js all you need to do with this is declare a list of targets you want to be able to run from the command line.
Conclusion
That is the basic pattern for building simple automated tests for Node.js code. In many cases, the Makefile
supplied above should get you testing away. (You may even notice that same Makefile
in a number of common node packages).
The Node.js assert
library that we looked at in Step 3 is very powerful, and has several other tests you can use. Check out the documentation on assert to learn more about the other available functions.