A simple DOH test fixture
by Sam Foster

To make unit test writing a useful and painless exercise, you need efficiency and repeatability. In this cookie I’ll introduce a simple test fixture class for use with Dojo’s unit test harness (DOH) that will mean less typing for you, and get you thinking about how to structure and write useful unit tests for your javascript.

You can define a test for DOH in two ways:

  1. A simple function to run, the function name is used as the test name
  2. A fixture (typically a dictionary object) that has an optional setUp, tearDown methods, and a runTest method that is the meat of the test. You can also name the test with a name property.

So, writing a unit test for DOH looks a bit like this:

doh.register("tests.somethingBasic", [
  function testSomething(t) {
       // assert that the something variable is truthy
    t.t(something); // or t.assertTrue
  }, 
  {
    name: "testSomethingElse", 
    setUp: function() {
      // do some setup before the test runs
    }, 
    runTest: function(t) {
       // assert that somethingElse is truthy
       t.t(somethingElse); 
    },
    tearDown: function() {
      // do some tearDown after the test runs
    }
  }
]);

The ability to do setup is of marginal value, if you have to write it out all over again for every test. And indeed if you look at the dojo test suite, you’ll mostly find the simple test function style being used, with any “setup” just being the first statements in that function. But, make that dictionary object a class instance, and you can define your setUp and tearDown once, and just spin off new instances for each test:

(function() {
	var _count = 0;
	dojo.declare("myns.tests.TestFixture", null, {
		name: "",
		timeout: 2000, // 2 seconds.
		setUp: function(props){ },
		constructor: function(name, props){
			if(!props) {
				props = name;
			}
			if(typeof props == "function") {
				var fn = props;
				props = {
					runTest: fn
				};
			}
			if(!props.name) {
				props.name = name || "test_" + _count++;
			}
			dojo.mixin(this, props);
			return this;
		},
		tearDown: function(){}
	});
})();

This construct gives us the ability to define tests like so:

doh.register("tests.MyThinger", [
  new test.TestFixture( "testSomething", function (t) {
       // assert that the something variable is truthy
    t.t(something); // or t.assertTrue
  }),  
  new test.TestFixture( "testSomethingElse", function (t) {
       // assert that somethingElse is truthy
       t.t(somethingElse); 
  })
]);

Here’s some closer-to-real-life usage. First extend the fixture class so it has the setUp we want to execute before each test:

dojo.declare("tests.MyThingerTestFixture", [tests.TestFixture], {
	setUp: function() {
		this.instance = new MyThinger();
	}
});
// make a shortend alias to save keyboard wear and tear
var TF = tests.MyThingerTestFixture;
 
doh.register("tests.MyThinger", [
  new TF( "testInstantiation", function (t) {
       // assert that the instance was created ok, and is what we think it is
      // note: 'this' here is the fixture itself
    t.t(this.instance);
    t.is("MyThinger", this.instance.declaredClass);
  }),  
  new TF( "testDoFoo", function (t) {
       // assert that doFoo does foo
       t.is("foo", this.instance.doFoo()); 
  })
]);

So far we’ve just been passing in a function to the fixture constructor, but we can also pass in a dictionary object (or parameter object/property bag if you prefer) that can customize the instance in the normal way:

doh.register("tests.MyThinger", [
  new TF( "testRender", {
    setUp: function() {
      // do the setUp as normal
      this.inherited("setUp", arguments);
      // ..and create an element we can render into  
      this.targetElm = dojo.create("div", null, dojo.body(), "last");
    },
    runTest: function(t) {
      // imagine the render method puts stuff into the element it is given
      this.instance.render(this.targetElm); 
      // assert that the target element got its payload
      t.is("foo", this.targetElm.innerHTML);
    },
    tearDown: function() {
      dojo.destroy(this.targetElm);
    }
  })
]);

This way you need only code what is unique about each test. If a series of tests (or maybe just more than one?) are “unique” in the same way, you can easily declare a new fixture subclass to house the code that would otherwise be duplicated.

These have been simple examples. The value of the fixture class increases at least in proportion to the complexity of your test. It doesn’t do the work for you, but it does provide a path to DRY-ness. I’ll leave you with one final wistful thought:

doh.register("tests.MyThinger", [
  new TF( "testClarityOfIntent", {
    description: "If only all tests had a description that indicated " 
      + "what they were actually supposed to be testing",
    runTest: function() {
        t.t( this.hasOwnProperty("description") && this.description.length > 10 );
    }
  })
]);

Tags: , ,

This entry was posted on Thursday, May 7th, 2009 at 1:32 am and is filed under Dojo Cookies. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

2 Responses to “A simple DOH test fixture”

  1. maulin Says:

    You can see a lot more about DOH, test fixtures, interesting assertions, etc in a post of mine from a year ago at http://blog.medryx.org/tag/doh/

  2. sfoster Says:

    @maulin - thanks for leaving that link. I had meant to do so myself, as I’m sure your article there was an inspiration for this one, if subliminally.

    There are 2 good articles in Sitepen’s blog that are good further reading also:

    Unit Testing Custom Code with the Dojo Objective Harness

    Creating Asynchronous Tests with the Dojo Objective Harness

Leave a Reply

You must be logged in to post a comment.