A few weeks ago, I gave a presentation on Firefox extension development at the Chicago Code Camp down in Grayslake, Illinois. Among the presentations I attended was on titled “TDD in Javascript.” It occurred to me as I watched this presentation that not only was I as guilty as the rest of the audience of skimping out on writing tests for Javascript — but worse, I hadn’t even included a testing chapter in my outline for my Firefox extension book!
When I got back, I immediately shifted some chapters around to make some space for a chapter on testing and debugging. I let my editor know that I was refactoring a little bit, and promptly forgot all about it as I scrambled to get another chapter finished up for a deadline.
Later, however, I started messing around with Screw.Unit. I examined the Smoke framework that provides mocking and stubbing functionality for Screw.Unit specs, and started to try and draft up some basic tests for one of my extensions.
The resulting code looked something like this:
describe("TULIP Extension",function(){
before(function(){
fakeTulip = Smoke.Mock(Tulip);
});
describe("handleReadyStateChange",function(){
describe("when request.readyState is the desired state",function(){
it("should call the handleTransaction function with the request",function(){
request = {readyState:DESIRED_STATE};
fakeTulip.should_receive('handleTransaction').with(request).and_return(true);
fakeTulip.handleReadyStateChange(request);
fakeTulip.checkExpectations();
});
});
});
});
I wasn’t a huge fan of this testing framework. For one thing, I didn’t like creating a mock object every time I wanted to stub out a particular function. For another, all of the nested function(){} calls left things looking extremely cluttered and unreadable. In the days of technologies like Cucumber, perhaps I’ve been spoiled into thinking that specs should be a bit more user-friendly.
Enter JSpec, a different style of Javascript testing framework. JSpec allows you to write your tests using Ruby-like syntax. When the specs get run, the Javascript gets precompiled into something that more closely resembles Screw.Unit code.
The only unfortunate thing was the stubbing framework. JSpec had a built-in spying framework, but no stubbing and mocking framework. It would be possible to use Smoke with JSpec, but Smoke has an additional failing — Often when we write our tests, we don’t actually have access to some of the instances we might like to stub. Sometimes instances are created by the methods we call, and it would require no small amount of code refactoring to allow us access to them.
JSpec follows Ruby syntax, so why not have a Mocha-like framework? I began working on my own mocking and stubbing framework that tries to parallel Mocha syntax for use with JSpec and other test frameworks. The project was a success.
JSocka (http://www.github.com/gisikw/jsocka) is a new stubbing and testing framework that allows for the following syntax:
JSocka("Person").expects("speak").with("Dignity").returns("function(){alert('I am the very model of a modern major general.')})
The framework supports stubbing and setting expectations on both class methods and instance methods, and allows checks for number of times called, what parameters were passed, and et cetera. With this mechanism, we can stub out any instance of a class, so that even if it’s not yet instantiated, we can stub out an object that would later be created in our tested class.
I was able to rewrite my test quite quickly using JSpec and JSocka:
describe ".handleReadyStateChange(request)"
describe "when the request readyState is the desired state"
it "should call the Tulip.handleTransaction method with the request"
JSocka("Tulip").expects("handleTransaction")
Tulip.handleReadyStateChange({readyState:Tulip.DESIRED_STATE})
JSocka.checkExpectations().should.equal true
end
end
end
For those interested, the Github repository for this extension contains a full test suite (http://www.github.com/gisikw/tulip).
The bottom line is that there are great Javascript testing frameworks out there and available, and it’s really tragic that so many developers let this fall by the wayside. With the advancement of Test-Driven Development, many programmers are focusing on writing very good test for the application-side of things, which is wonderful. It’s important though never to forget the final scripting language that adorns almost all web applications.
I’ve written up a significant amount regarding testing applied to extension development for my Pragmatic Bookshelf book, but it’s important that developers everywhere consider these valuable tools and start evaluating how best to test.
The tools are there. Use ‘em!
Hey great writeup. If you are interested we could put some effort towards adding more functionality to JSpec directly, saving others this same hassle.
It is not something I personally use much with JavaScript but it would be useful for others that is for sure. Currently I have deferred assertions for the should_receive matcher, we could just change that to a hook and allow deferred assertions and the reseting of the stubbed methods etc.
My implementation was pretty fast/weak so maybe we can tweak your library a bit and integrate it in fully.
PS. if JSpec is in your book I would love to check this out when its finished! let me know