Unit Testing in JavaScript. QUnit
If you are not familiar with definition of Unit Testing or you are wondering about solutions in JavaScript go to one of my previous articles.
The first type of JavaScript unit test frameworks are solutions like JSSpec or QUnit. They are written entirely in JavaScript and require a browser to run . The undoubted advantage of these solutions is an amazing simplicity of writing tests. But if we want them to run in different browsers, we are forced to do it manually. Unfortunately without some tricks we can’t run them from console, nor at once in different browsers or computers. However, there are adapters that let you to extend their functionality. Famed examples are JsTestDriver, Test Swarm and Selenium. Thanks to them we are able to control multiple browsers on multiple computers from one place. Anyway, I will describe them in future. Today we’ll take care of the basics.
Task
Let’s assume we want to extend the functionality of the Array class that it will act like a vector. We will create the add function which would add another array to the current. The function would be called in the chain. In addition, we will provide the normalize function, that (as the name suggest) would normalize our vector (so its length would be 1). Sample:
var one = [1, 2];
var two = [3, 5];
one.add(two).add([1, 0, 1]);
// one = [4, 7, 1]
two.normalize();
// two = [0.514496, 0.857493]
Framework
To create a framework for our tests, just paste following code in new html file:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<link rel="stylesheet" href="http://github.com/jquery/qunit/raw/master/qunit/qunit.css" type="text/css"/>
<script src="http://code.jquery.com/jquery-latest.js"> </script>
<script type="text/javascript" src="http://github.com/jquery/qunit/raw/master/qunit/qunit.js"></script>
<script type="text/javascript">
// --- Unittest Code goes here ---
</script>
</head>
<body>
<h1 id="qunit-header">QUnit example</h1>
<h2 id="qunit-banner"></h2>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
</body>
</html>
For test purposes you may use following page: jsfiddle.net/WNmcw/
Usage
Let’s take the example below:
We may run all tests using init function, but that’s not necessary because it is called automatically.
If you want to stop executing tests, call stop function. To resume, we call start function.
Sets of tests may be grouped by module function. The first argument of it takes the name of a group. The second one is an object that may have two keys: setup (function which is called at beginning of each test) and teardown (same, but at end). An example usage of mentioned functions is to create suitable objects on which the tests will be performed. ‘This‘ variable is always pointing at the same object, so appropiate communication is possible. However, it is cleared each time you run test.
Sets of tests are named by first argument of test and asyncTest functions. Second argument is a function in which we’re having revelant comprasions. Calling asyncTest function is equivalent to call test and stop one in another
asyncTest('Asynchronous test', function() {
setTimeout(function() {
start();
// Here tests
}, 3000);
});
// is equivalent to
test('Fake asynchronous test', function() {
stop();
setTimeout(function() {
start();
// Here tests
}, 3000);
});
We may perform the test itself by using one of three functions: ok, equal and same.
The first one is simple way to see if object exists and returns true. We may achieve same effect by using the equal function, which checks whether parameters have the same value:
ok(foobar);
// is equivalent to
equal(!!foobar, true);
// !!foobar converts foobar to boolean
The same function differ from equal in way it compares with the === operator insted of ==.
If there’s more than one test in set, we have to declare it using expect function:
test("Two tests", function() {
expect(2);
ok(window, "Window does not exists");
ok(document, "Document does not exists");
});
As seen above, various tests may be named by the last argument.
Our case
As we write test for our function, we must consider different cases. Firstly, do basic usage. Secondly, consider tests that may cause difficulty for our function. Thirdly, make sure that the function does not change what is not needed. A sample set of tests for our functions might look as follows:
In line with TDD principles, all tests ends with failure. We may proceed to write the appropriate functions. That might look for instance like this:
Array.prototype.add = function(vector) {
for(var i = 0; i < vector.length; i++) {
this[i] += vector[i];
}
return this;
}
Array.prototype.normalize = function() {
var sum = 0;
for(var i = 0; i < this.length; i++) {
sum += this[i] * this[i];
}
sum = Math.sqrt(sum);
for(var i = 0; i < this.length; i++) {
this[i] /= sum;
}
return this;
}
However after executing test, we get error messages like:
It is easy to guess that we forgot about the case in which vector length is zero. There also fails test as added vector is bigger than current. Knowing this, we can write code that passes the tests successfully:
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
March 20, 2010 in Guides, JavaScript, Programming, Unit Testing | View Comments
-
Pradeepin2








