Unit Testing with QUnit

Unit Testing Ajax Methods with QUnit

I took my first steps towards being a real javascript developer this past weekend. I began researching javascript testing frameworks with the intention of actually using one. I didn’t realize javascript had such a wide array of testing frameworks.

I was especially surprised to find out that some of the testing frameworks support TDD or BDD, but I digress. ..

This article is about using Qunit** to unit test http data requests. We’ll be getting some data from a REST service using Http Post.

For the sake of simplicity I will use jQuery’s ajax function for the sample code as I believe most javascript devevlopers are familiar with it’s usage.

My initial approach to get some data from a rest service had a couple inherent design flaws:

function getSomeData() {

$.ajax({

type: 'POST',

url: "../RestService/GetData",

success: function (data) {

//assign the data to a higher object property

myObj.myData = data;

},

dataType: "json"

});

};

 

When I looked at this from a testing perspective I discovered the following problems pretty quickly:

  1. To assert anything at all from a unit test we would have to explicitly create a dependency on an object (myObj) that has nothing to do with our test. All we want to do is validate the function got some data back. If myObj changed name, got added to a namesapce, or got deleted our test would fail for something that is out of our control.
  1. Qunit expects us to call stop() before initiating the asynchronous operation so that it can display the status of the asynchronous test in the Qunit results window and Start() when the async operation is complete. With the current setup we have no precise way of knowing when the success function is called. We could check the myObj.myData until it isn’t undefined, but I would rather throw my computer out the window than do that.

There are two patterns we can use to solve this problem I will talk about the pros and cons of both of them objectively and then give my personal opinion on which one I prefer.

Option 1: The Ajax complete pattern

The Ajax complete pattern is the when you return the XMLHttpRequest from an ajax post. Since we are using jQuery we will bind to the jqXHR object returned from the $.ajax() call. The jqHXR object is a superset of the browser’s native XMLHttpRequest object.  That let’s us easily bind to the done() event which fires upon a successful request (the name kind of implies that it will always fire but don’t be fooled).

To achieve this we must modify our getSomeData() method to return the result of the ajax call. Fortunately this is easily accomplished.

function getSomeData() {

return $.ajax({

type: 'POST',

url: "../RestService/GetData",

success: function (data) {

//assign the data to a higher object property

myObj.myData = data;

},

dataType: "json"

});

};

Now for the good stuff: The unit test.
We start by notifying QUnit  that this code is a test by wrapping it with the test() method.

The first parameter is the name of the test.

A good naming convention for tests is to be as specific as possible in regard to the unit of work currently under test.
We’ll name this test “Get Data with the ajax complete pattern”.

The second parameter is the test code wrapped in an Anonymous function.

test("Get Data with ajax.Done() pattern", function () {

//let QUnit know we are making an Asynchronous Test  call and are awaiting a response.

stop();

getSomeData().done(function (data, status, jqXHR) {

//let QUnit know that the Async test call is complete and test results are being gathered.

start();

//We are expecting 2 tests to pass.

expect(2);

//assert at least one series was returned

equal(data.length, 1, "At least one dataset was returned");

//assert that the series contains data

equal((data[0].someProperty.length > 0), true, "At least one set of data returned");

});

});

The start() and stop() methods are used so that the QUnit testing results page can accurately display the status of an Async test.

Option 2: The callback pattern

This pattern requires a more drastic change to our getSomeData() function, but ultimately provides what I think is the better implementation.

We need to modify our getSomeData() function to accept a callback function as a parameter. Then we assign the function parameter to the value of the success callback function of the ajax request. It’s easier to understand if we look at the code changes.

function getSomeData(successCallback) {

$.ajax({

type: 'POST',

url: "../RestService/GetData",

success: successCallback,

dataType: "json"

});

};

Notice how we didn’t define a function for success ? We just passed in a callback object. Now we can have the calling code of this function work with the returned response dynamically. Many different charts, widgets, or any data driven component can now hook into this data call and manipulate the data in different ways.

What this also means is that our test can be a lot cleaner. We can write a callback function that includes the test and inspect the actual response of our Http call. In the previous test we assumed we were able to inspect the data by returning our jqHXR object. Our data call was restricted to working with the data one way. Using this call back pattern our data call is extremely reusable, which I hear is a good thing…

The second test display just how flexible this technique because the callback function we pass it includes our test assertions. I am a really big fan of this pattern.

test("Get Data with the callback pattern", function () {

//let QUnit know we are making an Asynchronous Test  call and are awaiting a response.

stop();

DataEntryPrototype.getSomeData(function (data) {

//let QUnit know that the Async test call is complete and test results are being gathered.

start();

//We are expecting 2 tests to pass.

expect(2);

//assert at least one series was returned

equal(data.length, 1, "At least one dataset was returned");

//assert that the series contains data

equal((data[0].someProperty.length > 0), true, "Some distinct part of the of data was returned");

});

});

Both the solutions presented here accomplish the important goal  of asserting our data was returned. However the callback pattern is a really excellent example of how javascript can be powerful yet extremely concise and elegant.

** if you are not familiar with QUnit syntax at all check out this article: how-to-test-your-javascript-code-with-qunit

Advertisements

One comment

  1. jmezaschmidt · September 19, 2013

    Hi my question would be: using the callback pattern, on which line are you calling myObj.myData = data; it’s not clear to me, because you just only saying that on the $ajax success: successCallback but i dont know where myObj.myData = data its being called

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s