Home > Uncategorized > Testable Web UI IV: YUI Test (plus a bit of mocking)

Testable Web UI IV: YUI Test (plus a bit of mocking)

February 16th, 2009

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

andy Uncategorized ,

Comments are closed.