So, last time, I was trying to write a test around requesting some JSON data from a service, and return it. Unfortunately, JsUnit is not up to the task of handling asynchronous logic at all, so I decided to ditch it in search of greener pastures.
Having spent some time working with
YUI in the past, I settled on trying
YUI Test out.
It took some finagling, but I successfully managed to convert my first test over to the new testing framework. It's got quite a lot of boilerplate, so I won't inline it, but you can see it
here.
Now that we've regained lost ground, time to try what we were doing before. Here's my test:
testCanRequestJson : function() {
var self = this;
asyncRequestJson('getStats.json', function(result) {
self.resume(function() {
Assert.areEqual('andy', result.name);
Assert.areEqual(9999, result.hit_points);
Assert.areEqual(1, result.kickboxing);
Assert.areEqual(99, result.linear_algebra);
Assert.areEqual(99, result.cross_stitching);
});
});
self.wait();
},
The way it works is that the "self.wait();" call tells the testing framework to wait until a corresponding "self.resume(fn)." If the resume doesn't come within a few seconds, the test fails. It's a bit ugly, but it does the job admirably, and I don't know how you'd do it better without fibres or coroutines or something, so I'm not about to complain too loudly.
This is great, as it demonstrates I can interact with the network in a sensible way, but it's kind of annoying that I have to have an extra data file just to make the test run. I think it's fine for a functional test like this, but I don't want to have to write functional tests for everything.
The next step is to plug these values into my widget. Here's my test:
testWidgetIsPopulated : function() {
var grueStats = {
name:"Grue",
hit_points:1,
kickboxing:1,
linear_algebra:0,
cross_stitching:99999
};
var net = new FakeNetwork();
var sw = new StatusWidget('avatar-1',
function (url, onComplete) { return net.asyncRequestJson(url, onComplete); }
);
net.completeRequest('getStats.json', grueStats);
Assert.areEqual("Grue", sw.getName());
Assert.areEqual(1, sw.getHitPoints());
Assert.areEqual(1, sw.getKickboxingScore());
}FakeNetwork? Whassat? It's this:
function FakeNetwork() {
this.requests = {};
}
FakeNetwork.prototype = {
asyncRequestJson : function(url, onComplete) {
this.requests[url] = onComplete;
},
completeRequest : function(url, result) {
this.requests[url](result);
delete this.requests[url];
}
};Simple, yes? This way, I don't have to actually have a JSON service for every little thing, and I don't have to worry about asynchronous results or network funkiness. Win!
Tomorrow, I will do some badly-needed refactoring, and lay out what the future direction of the design should be.
Source code