Tuesday, September 20, 2011

Unit Testing using QUnit

It has taken a while but this is the continuation of my previous blog on implementing a Test Framework for JavaScript

In this blog I will discuss in detail about writing test case and how it can be executed with ant. But before entering lets be clear that we are writing only unit test cases to test functionality and NOT multibrowser compatibility.

Writing Test Cases using QUnit
QUnit is a simple test suite library from jQuery team. Its a neat library with all the api's you will need for writing a test case. Lets take a simple Calculator class and see how test cases can be written for it


 //calculator.js
 function Calculator() {}
 Calculator.add = function (x, y) {
    return x + y;
 }
 Calculator.subtract = function (x, y) {
    return x - y;
 }
 Calculator.multiply = function(x, y) {
    return (x * y).toFixed(10);
 }
 Calculator.divide = function(x, y) {
    return x/y;
 }



This is how the test file will look for calculator.js


 //testCalculator.js

 module("Calculator")
 test("Addition Test", function() {
    expect(2);
    equals(5 + 5, 10, "postive integer addition");
    equals(5.99 + 3.87, 9.86, "decimal addition");
 });
 test("Multiplication Test", function() {
    expect(1);
    equals(5.99 * 0.1, .599, "decimal multiplication");
 });



Lets get into details.
module -  module is a set of test cases. It is a logical grouping of test case. It is optional but comes in handy when there are test case failures and you want to trace the failure. We will look at this later

test function -  it is inside these test functions we write our test cases. It takes two parameters - name and callback function.

expect -  call this method to say how many assertions you expect to run within the test case. This is useful because at time you would want to write assertions with a loop. You can use this method to keep track of it.

Above 3 are the basic elements to get started with writing test cases.

Download QUnit and check the link for executing this test case. This will produce a html output.
But our intention is to run the test cases in console so as to integrate with ant. So we need to do some extensions.


Extending QUnit
To see the test case execution in console, we will need to extend some of the QUnit methods like log, moduleStart etc...
This is my QUnitExtension.js file


 //QUnitExtension.js
 QUnit.log = function(details) {
print(details.result ? 'PASS ' + details.message
            : 'FAIL ' +  details.message + '\nExpected: ' + details.expected +   '\nActual: ' + details.actual);
 };


 QUnit.moduleStart = function(details) {
print("Module ", details.name, " started...");
 };


 QUnit.moduleDone = function(details) {
print(details.name, " ends", "TOTAL:", details.total, " PASSED:",  details.passed, " FAILED:", details.failed);
 }; 


 //hack for avoiding execution interruption due to errors
 var current_object_parser = QUnit.jsDump.parsers.object;
 QUnit.jsDump.setParser('object', function(obj) {
   if(typeof obj.rhinoException !== 'undefined') {
     return obj.name + " { message: '" + obj.message + "', fileName: '" +  obj.fileName + "', lineNumber: " + obj.lineNumber + " }";
   }
   else {
     return current_object_parser(obj);
   }
 });


Executing the Test Cases
Now we have got test cases and utilities. To execute the test cases in console we need a JavaScript engine and a headless browser. For this we use Rhino as the JavaScript engine and Envjs for headless browser. Rhino+Envjs as a package is available at http://www.envjs.com/releases
Download and build it.

Create a folder test.
Download qunit.js and copy to test folder.
Copy calculator.js, testCalculator.js and QUnitExtension.js to test folder.

We need  a initialization script to load the test files and source files for execution.

//init.js

load('dist/env.rhino.js');
load('test/qunit.js');
load('test/QunitExtension.js');

//config
QUnit.init();
QUnit.config.blocking = true;
QUnit.config.autorun = false;
QUnit.config.updateRate = 0;

load('test/calculator.js');
load('test/testCalculator.js');

QUnit.start();



Once init.js is available we are ready to go.

Run command java -jar rhino/js.jar init.js to see the output.

Integrating with ant
Write a build.xml file with the below target.

    <target name="js-test" description="Runs javascript unit tests">
        <java classname="org.mozilla.javascript.tools.shell.Main" failonerror="true" fork="true">
            <classpath refid="jstest.classpath"/>
            <arg value="-opt"/>
            <arg value="-1"/>
            <arg value="-f"/>
            <arg value="thatcher-env-js-cb738b9/test.js"/>
        </java>
    </target>

To execute use command ant js-test
Its done!

1 comment: