JavaScript Unit Testing

30 Dec 2009 | By Alex Young | Tags libraries testing

Our JavaScript Developer Survey results showed that a large percentage of readers don’t currently unit test their JavaScript. I’ve been unit testing my own JavaScript projects for a few years, which resulted in the creation of riotjs — for more on riotjs see my blog post: Riotjs: A JavaScript Unit Testing Framework

There are lots of JavaScript test frameworks. I’ve presented a summary below — there are both traditional unit testing libraries and behaviour-driven frameworks.

unittest.js

unittest.js by Thomas Fuchs has been used by many JavaScript developers since Scriptaculous became popular in 2006. It provides a test framework that is recognisable to Ruby developers, and the relationship between Rails and Scriptaculous further increased adoption in this group.

This library depends on Prototype and is usually run inside HTML templates rather than a JavaScript interpreter.

Tests look like this:

  new Test.Unit.Runner({
    testExample: function() { with(this) {
      var exampleVar = '1234';
      assertEqual('1234', exampleVar);
      assert(true);
    }}
    
  }, "testlog");

Fuchs uses with(this) to cut down unnecessary syntax — you don’t have to write tests this way though.

Setup and teardown methods are supported. Shoulda-style assertion names have also been added. This adds methods to the prototypes for common JavaScript objects, so it’s possible to write 'test'.shouldEqual('test').

unittest.js also includes a handy benchmark method, and the following assertions:

assertNotEqual(expected, actual) Inverse of assertEqual
assertNotVisible(element) Checks if an element has display: none
assertVisible(element) Inverse of above
assertInspect(expected, actual) Checks if expected is the same as actual.inspect()
assertEnumEqual(expected, actual) Ensured two enumerables are equal
assertIdentical(expected, actual) Comparison using ===
assertNotIdentical(expected, actual) Inverse of above
assertNull(obj) Is obj null?
assertNotNull(obj) Inverse of above
assertMatch(expected, actual) Performs a regex, where expected is the regex
assertType(expected, actual) Checks if actual.constructor == expected
assertNotOfType(expected, actual) Inverse of above
assertInstanceOf(expected, actual) Checks if actual is instanceof expected
assertNotInstanceOf(expected, actual) Inverse of above
assertRespondsTo(method, obj) Checks if obj has a method named method
assertReturnsTrue(method, obj) Ensured that the method named method called on obj returns true
assertReturnsFalse Inverse of above
assertRaise(exceptionName, method) Ensures calling method raises an exception named exceptionName
assertElementsMatch([elements], expression1, expression2, ...) Ensures the array of elements match the list of expressions
assertElementMatches(element, expression) A helper for the above assertion when supplying a single element

JsUnitTest

JsUnitTest is a port of unittest.js without the Prototype dependency.

JsUnit

Development for JsUnit started in 2001, and is based on JUnit. Like unittest.js, tests are designed to be run in a web browser. By using the build.xml Ant file, tests can be run against multiple browsers on a local machine, or on multiple remote machines.

JsUnit tests are grouped within a Test Page. Test pages contain your tests. If a Test Page has setUp or tearDown functions, they will be run before and after each test function. A function called setUpPage will be run once per Test Page.

Each test function is written prefixed with test:

function testExample() {
    assert(true);
}

The following assertions are available:

  • assert([comment], booleanValue)
  • assertTrue([comment], booleanValue)
  • assertFalse([comment], booleanValue)
  • assertEquals([comment], value1, value2)
  • assertNotEquals([comment], value1, value2)
  • assertNull([comment], value)
  • assertNotNull([comment], value)
  • assertUndefined([comment], value)
  • assertNotUndefined([comment], value)
  • assertNaN([comment], value)
  • assertNotNaN([comment], value)
  • fail(comment)

QUnit

QUnit is used by jQuery for its unit tests. To use QUnit, include qunit.js and qunit.css within a HTML file that can display the test results.

Tests look like this:

test("a basic test example", function() {
  ok(true, "this test is fine");
  var value = "hello";
  equals("hello", value, "We expect value to be hello");
});

The jQuery QUnit documentation has full examples.

jspec

jspec (by Yehuda Katz) is an RSpec inspired framework. Rather than traditional unit tests, jspec attempts to provide a behaviour-driven development approach.

This is best illustrated with an example:

jspec.describe("The browser environment", function() {
  it("should have Array.prototype.push", function() {
    Array.prototype.push.should("exist");
  });
 
  it("should have Function.prototype.apply", function() {
    Function.prototype.apply.should("exist");
  });
})

Tests are written with it() blocks and chained should() calls.

The GitHub repository is currently pretty spartan, with no documentation or README, but jspec is a good port for those of you who are familiar with RSpec or want a change from JUnit-style libraries.

JSpec

JSpec by visionmedia (who have cropped up frequently on DailyJS) is a much more fleshed out BDD library. The author has tried to keep it minimal, but it has a unique and friendly DSL. It’s possible to write “grammar-less” tests using plain JavaScript.

Jasmine

Jasmine builds on the ideas of the previous libraries to provide a BDD library that supports asynchronous tests — Ajax-friendly testing.


blog comments powered by Disqus