Advanced Unit Testing Tools For Node.Js

Wercker is a Docker-Native CI/CD Automation platform for Kubernetes & Microservice Deployments

Yoshua Wuyts
Yoshua Wuyts
December 24, 2014

Writing tests is a staple in providing quality code. Code of all varieties can benefit heavily from having an extensive test suite. Only by having automated tests in place can you guarantee that the assumptions you are making about your code are true.


Tests can generally be divided into three categories: unit, service and UI. Martin Fowler talks about this extensively in his article TestPyramid:

In particular I always argue that high-level tests are there as a second line of test defense. If you get a failure in a high level test, not just do you have a bug in your functional code, you also have a missing unit test. Thus whenever you fix a failing end-to-end test, you should be adding unit tests too.

In this article we’ll be covering a few of the available tools for creating maintainable unit tests in Node.js.

TAP

The Test Anything Protocol (TAP) has been used since 1987 for communicating between tests and interpreters. npm has over 500 modules that work with TAP. One of the more popular TAP libraries in the Node ecosystem is tape. Modules such asbrowserify, virtual-dom all rely on tape.

tape’s assertions work very similarly to Node’s own core assert module. Here’s an example of tape in action:

test.js
const test = require('tape')

test('assert a string type', function(t) {
  // Amount of assertions we plan to run.
  // will throw if count doesn't match.
  t.plan(2)

  const bar = 'foo'
  t.equal(typeof bar, 'string', 'assert `bar` type')

  const err = false
  t.ifError(err, 'should not be an error')
})

And here’s how you’d run the aforementioned test:

# install dependencies
npm i tape && npm i -g tap-bail faucet

# run the tests
node test.js | tap-bail | faucet

Stubs

Even the cleanest application will have some form of external, less predictable, dependency. In order to test our code in isolation we need a way to stub out external dependencies.

proxyquire is a package built specifically to stub out require() statements in Node, without needing to modify your source code. Below is an example of proxyquirestubbing out fs.writeFile to call its callback immediately without accessing the filesystem.

stub-test.js
const proxyquire = require('proxyquire')
const test       = require('tape')

const fs = proxyquire('fs', {
  writeFile: function(name, data, cb) {
    cb(null, 'huzzah')
  }
})

test('fs.writeFile() should be stubbed', function(t) {
  t.plan(2)
  fs.writeFile(null, null, function(err, body) {
    t.ifError(err, 'no error')
    t.equal(body, 'huzzah', 'body value')
  })
})

When dealing with large applications that have lots of dependencies proxyquirewill prove invaluable in helping untangle files into nicely tested modules.

Client testing

Modern web applications are equal parts backend and frontend. Client side JavaScript has historically been tricky to test, often times relying on relatively large tools such as selenium or phantomjs to run simple validations.

smokestack is a tool that makes browser testing easy! It takes JavaScript input, pipes it to a browser to be executed, and then pipes the browser’s console output back to your terminal. Here’s an example of a tape test prepared to be executed throughsmokestack:

client-test.js
const test = require('tape')

test('this should pass', function(t) {
  t.plan(1)
  t.ok(true, 'an assertion')
})

test('this should fail', function(t) {
  t.plan(1)
  t.ok(false, 'an assertion')
})

test('shutdown', function(t) {
  setTimeout(function() {
    window.close()
  }, 10)
  t.end()
})
# install dependencies
npm i tape && npm i -g browserify smokestack faucet

# bundle commonjs & run tests
browserify test.js | smokestack -b firefox | faucet

Which then returns nicely formatted TAP to your console, fresh from your browser.

Wrapping up

Writing quality tests is a skill every Node developer needs to develop in order to continue improving their code. With these tools you too can easily write tests that will run anywhere, are untangled from dependencies and tap into a large ecosystem of existing modules that match your needs.

Have any questions? Drop us a line at pleasemailus[at]wercker.com.

Earn some stickers!

Take a screenshot of your passing Node tests, tweet it out with #wercker and we’ll send you some @wercker stickers.

Follow us on twitter as well to stay in the loop.

 

Topics: Tutorials