From fd0dc18edd0ba3bffce9c445bbeaceb1b92d0694 Mon Sep 17 00:00:00 2001 From: kriskowal Date: Wed, 16 Dec 2009 01:35:23 -0800 Subject: [PATCH] Documented testing. --- docs/test.md | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/test.md diff --git a/docs/test.md b/docs/test.md new file mode 100644 index 00000000..f4515d9f --- /dev/null +++ b/docs/test.md @@ -0,0 +1,107 @@ + +Testing +======= + +Narwhal supports the [CommonJS Unit Test API +1.0](http://wiki.commonjs.org/wiki/Unit_Testing/1.0). You can run any unit +test script with the `"js -m test"` command. + + js -m test tests/all-tests.js + +Some tests include a snippet on the bottom that allows them to self-run, in +which case it is sufficient to run the script directly. + + js tests/all-tests.js + +The boilerplate looks like this: + + if (require.main == module) + require("os").exit(require("test").run(exports)); + +You can construct your own unit tests by creating a JavaScript module that +exports `test*` functions, and uses the `assert` module to throw an +`AssertionError` if a test fails. + + exports.testFoo = function () { + assert.ok(true); + assert.equals(2 + 2, 5, "three sir!"); + }; + +Alternately, if you prefer a test to continue running all test points even +after one of the assertions fails, you can use the logging assertion mechansim, +which is an `assert` object with the same API as the assert module that +gets quietly passed to your test functions. It is a different logger object +for each module. + + exports['test my feature'] = function (assert) { + assert.ok(false); + assert.ok(true); + }; + +Customization +------------- + +The CommonJS Unit Testing specification codifies a very small subset of the +components you need for a unit testing framework, so that multiple frameworks +can run interoperably. Two of the other pluggable parts are the test logging +system and custom syntactic sugar for advanced assertions. + +### Logging + +To have the test runner direct logs to an alternate system, pass an alternate +logger object to the `test` module's `run` method. + + require("test").run(exports, new Log()); + +The logger object needs to conform to the logger API set out in the `test` +module. That involves providing implementations of the following function +properties: + + * `pass(message_opt)` + * `fail(assertion)` + * `error(exception)` + * `section(name:String):Log` + +The assertion object has the following properties: + + * `name` `AssertionError` + * `message` + * `actual` + * `expected` + * `operator` + +### Assertions + +You can create complex assertions by providing functions that can throw +`AssertionError`. One fashionable technique is to provide a chaining API. + + expect(x).is(y); + +To enable this simple case: + + var assert = require("assert"); + + var expect = function (actual) { + var self = {}; + self.is = function (expected, message) { + if (!is(expected, actual)) { + throw new assert.AssertionError({ + "expected": expected, + "actual": actual, + "message": message, + "operator": "is" + }); + } + }; + return self; + }; + + // from Caja + function is(x, y) { + if (x === y) { + return x !== 0 || 1/x === 1/y; + } else { + return x !== x && y !== y; + } + } +