Getting Started With jQuery QUnit for Client-Side Javascript Testing


Setup

First of all, I’m assuming you’re already using jQuery. If not, you should be 🙂 QUnit may help you for non-jQuery testing, but it’ll work better with jQuery.

Second, you should start by downloading and setting up QUnit (from this link).  QUnit consists of a single JS file (testrunner.js) and a CSS file (testsuite.css).

Third, I recommend grabbing a patched testrunner.js from here (Ticket 3215).  We, at Dovetail, submitted this patch to the jQuery team. Some of the changes were accepted, some weren’t (and then the ticket was surreptitiously closed! How rude!).  One particular feature that was NOT accepted was the beforeEach/afterEach additions to achieve xUnit-style SetUp and TearDown (before each test/after each test) behavior.  I don’t know about you, but I consider SetUp/TearDown a critical feature for any would-be xUnit framework, regardless of language/platform.

Your First QUnit Test

To start testing, you’ll need to start by creating an HTML page (MyFooTests.htm, for example).  This page will need to reference the jquery core JS file, testrunner.js, testsuite.css, as well as the JS file containing the code you’re going to be testing. Lastly, the page will need some special HTML at the bottom with well-known ID’s so that QUnit can display its output.  When you’re done, you should have a rough skeleton like this:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title>My Foo Tests</title>    
    <script language="javascript" src="../jquery-latest.js" type="text/javascript"></script>
    <script language="javascript" src="testrunner.js" type="text/javascript"></script>
    <!-- add a script reference to your library here -->
    <link media="screen" href="testsuite.css" type="text/css" rel="stylesheet"/>    
</head>
<body>

<script language="javascript" type="text/javascript">

qUnitTesting(function(config){

    config.beforeEach = function(){
    }
    
    config.afterEach = function(){
    }
    
    //TODO: Modules and tests go here
});

</script>

        <h1>My Foo Tests</h1>
        <h2 id="banner"></h2>
        <ol id="tests"></ol>
        <div id="results"></div>
        <div id="main"></div>        
        
        <!-- Any HTML you may require for your tests to work properly -->
        
</body>
</html>

If you save that HTML and open it in a browser, you should see something to the effect of:

image

Modules and Tests

QUnit has the concept of “modules” and “tests.”  Tests are, like you would expect, the individual test cases. Modules are merely grouping mechanisms to organize the display of tests on the results screen.

Let’s create our first module and first test case.  To keep things simple and illustrative for this blog post, I’m merely going to test that the show() and hide() methods in jQuery work properly.  Normally you would want to avoid testing framework stuff (assume it’s already well-tested unless proven otherwise).

First, near the bottom of the HTML, before the closing </body> tag, add a div with an id “testDiv”:

<div id="testDiv"></div>

Then, up higher, where the “TODO” is in our JavaScript, add a new test, like so:

module("Show and Hide");

test("should hide the element when hide is called", function(){

    $("#testDiv").hide();

    // actual, expected
    equals($("#testDiv").css("display"), "none", "The element should be hidden");
});

test("should show the element when show is called", function(){

    // Arrange
    $("#testDiv").css("display", "none");
    
    // Act
    $("#testDiv").show();

    // Assert
    // actual, expected
    equals($("#testDiv").css("display"), "block", "The element should be visible");
}); 

Which should yield two successes:

image </p> </p> </p> </p> </p> </p>

Where to go from here?

For me, QUnit opened up the possibility for serious TDD with client-side JavaScript. Previously, quality with my JavaScript code was always an issue and it never seemed that manual testing was enough.  With QUnit, I can breathe a little easier now.

If I can catch some time in the next few weeks, I’ll do a post or two on how mocking works in JavaScript (or rather, why it’s so dirt simple it’s almost not worth talking about), and then even show how to integrate your QUnit tests into your CI build (which isn’t as hard as you might think).

Good Design is not Subjective