Automated Testing of Standard Output in Node.js

Summary: Many Node.js Applications rely heavily on Standard Output (stdout) like console.log, util.log, etc., for reporting application state, events and errors. By leveraging the power of JavaScript and a simple hook module, you can write unit tests that verify your application output.

Over the last several months, I’ve been spending a lot of time in Node.js. It started with my Knockout.Unobtrusive and Pinify plugins, which I ported to CoffeeScript, leveraging Node to set-up Cake builds and testing via Qunit. As a part of that effort, I also wrote my own Node package for sending Growl notifications on Windows, 80s Hair-band style. It’s called wingrr, and you can get it at http://github.com/bsatrom/wingrr, or just run “npm install wingrr” in a console window.

Recently, I’ve been working on a few other projects–one, a simple port of the node_chat application to CoffeeScript as an excuse to start using Jasmine; and another project using express and jade that I’m just getting rolling on this week. More on that one later.

In the meantime, I wanted to share something I learned while writing Jasmine tests (using the jasmine-node package) for the node_chat application. node_chat is a simple chat server (a node chat server, who would have thought?) implementation and, as such, it relies on standard output, or stdout, to report errors and information to the “user.” For example, one method provided by the server for this application is “listen,” which, given a port and optional host, will listen to all http traffic at that location. Here’s my implementation, in CoffeeScript. (JavaScript purists can click here for a not-generated-by-the-coffeescript-compiler equivalent)

1 2 3 4 5 6 7 8 9 10
exports = module.exports
 
# server logic omitted for brevity
 
exports.listen = (port, host, callback) ->
try
server.listen port, host, callback
util.log "Server listening at http://#{host or "127.0.0.1"}:#{port}/"
catch err
util.log err.message
view raw server.coffee hosted with ❤ by GitHub

Notice that I’m calling “util.log” (equivalent to sys.log in earlier versions of Node) to report that the server is listening, or any errors that may have occurred. As expected, this outputs to the console that the server is listening, as you can see in the image below.

Console Output in Node.js

This is great, but I wanted to write unit tests that would start and interact with my server, and the best way to verify that my tests passed would be to inspect these messages. I could return these messages from each method, and then inspect the returned value—and I even did that for the first couple of tests—but that would mean that I’ve written production code for the sole purpose of asserting my expectations in a test, which feels dirty.

Instead, I thought it made more sense to hook into stdout myself, and inspect the output for my tests. I hoped that Node might provide some kind of object-based message pump for me to query, but I found no such feature (though do please leave me a comment here if I’ve overlooked something). So I was out of luck in terms of a standard, Node-provided way to inpect stdout from my tests.

Undaunted,  I thought a bit more about my problem. I figured I needed to:

  1. Determine the mechanism Node uses to write to stdout
  2. Figure out how to “inject” an assertion into that mechanism

With JavaScript, #2 would be a simple matter of “rewriting” the functionality used by #1. So it was really just a matter of figuring out the global objects that Node provides for stdout.

Page 1 of 2 | Next page