Unit Testing JavaScript With QUnit And Phing

Recently I’ve been using both Phing for my PHP builds, and QUnit for my JavaScript unit tests, so I’ve been looking for a way to run these QUnit tests when Phing builds my application.

By default Phing can run PHPUnit tests, but not QUnit. However Martin Jonsson has come to the rescue with his Qunit Phing Task.

QUnit Phing Tasks lets QUnit tests be run during a build and Phing can either pass or fail based on these results. As QUnit is written in JavaScript, QUnit Phing Task runs PhantomJS to call a JavaScript wrapper that passes the output back to PHP and Phing. PhantomJS is a headless JavaScript browser that can excute on a command line.

Using QUnit Phing Task

To run the QUnit Phing Task you need to install PhantomJS. I downloaded a binary and placed it in /usr/local/bin on my system.

You need to download the QUnit Phing Task. I placed the files in a local ./lib directory in my project.

You will also need to download QUnit. I placed the files in a local ./tests directory in my project.

In the ./tests directory I created an HTML file called runner.html. This is the page we need to call to run our tests.

<!DOCTYPE html>

<html>
        <head>
                <meta chatset="utf-8" />
                <title>Qunit Tests</title>
                <link rel="stylesheet" href="./qunit.css">
                <script src="./qunit.js"></script>
                <script src="./test.js"></script>
        </head>

        <body>
                <div id="qunit"></div>
        </body>
</html>

I also create a JavaScript file called ./test.js in ./tests to hold my JavaScript tests in.

test("testing for true", function() {
        ok(true, "true is true");
});

Finally, I create a build.xml for my Phing build.

<?xml version="1.0" encoding="UTF-8"?>
<project name="qunit example" basedir="." default="qunit">

        <path id="project.class.path">
                <pathelement dir="./lib/" />
        </path>

        <taskdef name="qunit" classname="QunitTask">
                <classpath refid="project.class.path" />
        </taskdef>

        <target name="qunit" description="JavaScript Unit Test">
                <qunit executable="DISPLAY=:0 /usr/local/bin/phantomjs" haltonfailure="true" runner="./lib/run-qunit.js">
                        <fileset dir=".">
                                <include name="tests/runner.html" />
                        </fileset>
                </qunit>
        </target>

</project>

In this I am specifying a path to my ./lib directory as this is where the QUnit Phing Task code is. The path is then used in the taskdeftask which is used to create the <qunit> task. Now when I call <qunit> in my qunit target I just pass in the location of the executable – in this case where PhantomJS is, whether Phing should halt if the QUnit tests fail, and where to find the the JavaScript that runs QUnit. Inside the task, we pass in where our runner pages are, as we only have the one in this example we include it by name tests/runner.html.

Running this gives us the following…

rob@lamp ~/qunitphing> phing
Buildfile: /root/qunitphing/build.xml

qunit example > qunit:

    [qunit] ./tests/runner.html: 1 tests of 1 passed, 0 failed

BUILD FINISHED

Total time: 0.3275 seconds

So we can see our tests have passed. Let’s change our test.js so that it fails.

test("testing for true", function() {
        ok(true, "true is true");
        ok(false, "false is true");
});

This test should fail, as false is not true and will fail the ok assertion.

rob@lamp ~/qunitphing> phing
Buildfile: /root/qunitphing/build.xml

qunit example > qunit:

    [qunit] 1 tests failed on: ./tests/runner.html
    [qunit] Failed test: testing for true (1, 1, 2)
Execution of target "qunit" failed for the following reason: /root/qunitphing/build.xml:13:41: QUnit tests failed

BUILD FAILED
/root/qunitphing/build.xml:13:41: QUnit tests failed
Total time: 0.3258 seconds

So we can see that Phing has failed our build due to the QUnit tests failing, which is what we want.

Summary

Although a very simple and contrived example, I hope this has shown you how to add JavaScript unit tests using QUnit to your Phing build.

Using QUnit To Unit Test JavaScript

In this article I wanted to give you an introduction to unit testing in JavaScript using QUnit.

QUnit was originally developed by John Resig for testing jQuery, but it is now a stand alone project, without any dependancies on jQuery.

A quick example of using QUnit

Firstly, you need to download qunit.js and qunit.css, and store them locally.

Secondly you need to create an HTML page something like this to run your tests in.

<!DOCTYPE html>

<html>
	<head>
		<meta charset="utf-8">
		<title>QUnit Example</title>
		<link rel="stylesheet" href="./qunit.css">
		<script src="./qunit.js"></script>
		<script src="./test.js"></script>
	</head>
	<body>
		<div id="qunit"></div>
	</body>
</html>

You’ll notice the references to qunit.css and qunit.js are to the two files we downloaded just now. tests.js is the file where we’ll be placing our unit tests, and we’ll be creating this shortly. Finally, you’ll also see a <div> with an id of qunit. Ths is where the results of our unit tests will be displayed.

One of the simpliest tests is testing for true. Create a file called test.js and add the following.

test("testing for true", function() {
	ok(true, "true is true");
});

This should give us a result like looking like this.

QUnit Results

We can see that one test was successfully run, and that there were no errors found.

The name of our test, “testing for true” is shown, and clicking onto this expands the result and shows our success message “true is true”.

Qunit Results

So what is going on?

Well, we are calling the test function from QUnit, and we are passing in a name for our test – “testing for true”, and a function to execute the test in. Inside this function we calling the assertion ok from QUnit, passing in a value to test for truth against – in this case true, and a message about the assertion – “true is true”.

When the page is loaded into a browser, the script is run and the results of our unit test shown in the qunit <div>.

Testing For Equality

One of the most common unit tests is to compare the expected and actual values from a function.

QUnit has the equal assertion to help us here. Let’s add some more tests to test.js.

test("testing equality", function() {
	equal(1, 1, "1 is 1");
	equal("1","1", ""1" is "1"");
	equal(1, "1", "1 is "1"");
	equal(1, true, "1 is true");
	equal(1, !false, "1 is not false");
});

Run this and expand the results for “testing equality”, it should look something like this…

Qunit Results

You should see the obvious results such as 1 and 1 being equal, and “1” and “1” being equal. You should also see that 1 is the same as “1” as JavaScript is converting between types and checking the values are the same. Finally, you can see that 1 is also true, and not false, this is because 1 is truthy in JavaScript. The point to remember here is that the equal assertion behaves like JavaScript’s == comparator.

There may be occassions where you need to compare the value and the type, so the number 1 isn’t the same as the string “1”. In these situations we need to use the strictEqual assertion as this works like JavaScript’s === comparator.

Let’s add some more assertions to our “testing equality” test.

	strictEqual(1, "1", "1 is "1"");

Running this we can see that the number 1 is not the same as the string “1”, and QUnit has thrown an error to tell us this.

Qunit Results

However this isn’t very useful, as we know that 1 isn’t really “1”, so we want to test for this. This is where QUnit’s notStrictEqual assertion will come in handy, as it tests for false results.

Replace the strictEqual with the following…

	notStrictEqual(1, "1", "1 is not "1"");

Running this we can see that the number 1 is not the same as the string “1”, and QUnit has tested successfully for this.

QUnit Results

It’s useful to be able to compare objects, so let’s try this but adding the following code…

	var a = {'name' : 'rob'};
	var b = a;
	equal(a, b, "variables a and b are equal");
	b = {'name' : 'rob'};
	equal(a, b, "variables a and b are equal");

Running this we see that our first asserting that a and b are equal is correct, however, creating what looks like the same object and testing equality fails.

QUnit Results

This is because we’re not testing the actual contents of the object, just that the reference the variable points to is the same. In the first case they both point to the same object, in the second case they are different objects.

QUnit has another equality function called deepEqual that compares the content of an object with the content of another object. Let’s change the failing equal in our last example with the deepEqual and try again.

	deepEqual(a, b, "contents of variables a and b are equal");

QUnit Results

Our tests are working again now, as we are now comparing the actual contents of the objects.

Summary

QUnit can do much more than just testing for equality and I hope to touch on some of the other functionality in another article soon. However, I hope this basic overview has been a useful introduction to unit testing JavaScript and has provided enough information to get you started in testing your own JavaScript code.