Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / unit-testing

Introduction to Qunit

4.29/5 (6 votes)
31 Jul 2013CPOL2 min read 17.9K  
Qunit by example

Introduction

Testing the software we develop has become a very important part of our daily work. It doesn't matter if you work on Java, C#, PHP or any other language. I bet you have great tools for testing your code, Java guys may have Junit, .NET kids may probably use Nunit and some other PHP developers may work with PHPUnit or something else.

Some weeks ago, I started working on a web app and yes... I had to write tests for my JavaScript code too, so I started to evaluate some of the options out there like Jasmine and of course Qunit which is the one that I am going to write about.

Background

Learn by doing is my favorite way to gain knowledge about new technologies, so I am going to show an end to end example about testing a simple calculator app.

Calculator

For this simple calculator, we are going to create two files:

  1. index.html: contains plain HTML code with inputs and a button to calculate results
  2. calculator.js: contains the logic to perform basic arithmetic calculations

Index.html

HTML
<!DOCTYPE html>
<html>
	<head>
		<title>Calculator</title>
		<script type="text/javascript" 
		src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
		<script type="text/javascript" src="./calculator.js"></script>
	</head>
	<body>
		<label for="number_a">Number 1:</label>
		<input type="text" id="number_a"><br>
		<label for="number_b">Number 2:</label>
		<input type="text" id="number_b"><br>
		<label for="operation">Operation:</label>
		<select name="operation" id="operation">
			<option value="+">+</option>
			<option value="-">-</option>
			<option value="*">*</option>
			<option value="/">/</option>
		</select>
		<button onclick="getResult();">Calculate</button><br>
		<label for="result">Results:</label>
		<input id="result">
		<hr>
		<div id="validation"></div>
		<script type="text/javascript">
			function getResult () {
				var a = $('#number_a').val();
				var b = $('#number_b').val();
				var op = $('#operation').val();
				var result = calculate(a, b, op);
				$('#result').val(result);
			}
		</script>
	</body>
</html> 

calculator.js

JavaScript
function add (a, b) {
	return a + b; 
}

function substract (a, b) {
	return a - b; 
}

function divide (a, b) {
	if(b === 0){
		$('#validation').text('Attempt to divide by zero');
		return "error";
	}
	return a / b;
}

function multiply (a, b) {
	return a * b;
}

function notSupported () {
	$('#validation').text("un-supported operation");
	return "error";
}

function validate_input (number) {
	var is_valid = true;
	number =  number.toString().trim();
	if(number.length == 0){
		$('#validation').text("Blank input found");
		is_valid = false;
	}
	else if(!/^\d+$/.test(number)){
		$('#validation').text("Invalid input ("+ number+")");
		is_valid = false;
	}
	
	return is_valid;		
}

function calculate (a, b, op) {
	if(!validate_input(a))
		return;
	if(!validate_input(b))
		return;
	a = parseInt(a);
	b = parseInt(b);
	switch(op){
		case "+":
			return add(a,b);
			break;
		case "-":
			return substract(a,b);
			break;
		case "*":
			return multiply(a,b);
			break;
		case "/":
			return divide(a,b);
			break;
		default:
			return notSupported();
			break;
	}
}
Calculator should look like this:
Image 1

I know, I know the UI is ugly but come on guys!!! This is a tip about qunit.

Adding Tests to Our Calculator

At this point our application should work, but now it's time to add some tests to make sure our app will behave as expected and also to make sure future changes won't break the application.

We are going to add two more files that will take care of testing our existing app:

  1. index_test.html: The file you need to open with a browser to execute the tests
  2. calculator_test.js: contains all the asserts that will be executed against our real application code

index_test.html

HTML
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>
			Calculator Tests
		</title>
		<!--jquery and qunit files-->
		<script type="text/javascript" 
		src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
		<script type="text/javascript" 
		src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
		<link rel="stylesheet" 
		type="text/css" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
		<!--include the file we are testing along with its test file-->
		<script type="text/javascript" src="./calculator.js"></script>
		<script type="text/javascript" src="./calculator_test.js"></script>
	</head>
	<body>
		<!--Test results will go here-->
		<div id="qunit"></div>
		<!--
			* Required html elements that need to be present when running the tests
			* Values in html elements are reset to their default values 
                        * before each individual tests
		-->
		<div id="qunit-fixture">
			<input type="text" id="number_a">
			<input type="text" id="number_b">
			<select name="operation" id="operation">
				<option value="+">+</option>
				<option value="-">-</option>
				<option value="*">*</option>
				<option value="/">/</option>
			</select>
			<input id="result">
			<div id="validation"></div>
		</div>
	</body>
</html>
qunit div

Qunit will run your tests and print a fancy report inside the div with the id="qunit".

qunit-fixture

Inside this div, you can write any HTML code that you want so it's there when you run the tests. It is useful to execute DOM tests and validate UI behavior after calling a specific function.

An important thing to know about this section is that HTML content inside this div will be reset before each individual test to ensure that every single test works fine and avoid dangerous dependencies.

calculator_test.js

JavaScript
test("verifies that calculator can add", function() {
    equal(calculate(1,1,"+"), 2);
});

test("verifies that calculator can substract", function() {
    equal(calculate(1,1,"-"), 0);
});

test("verifies that calculator can multiply", function() {
    equal(calculate(1,1,"*"), 1);
});

test("verifies that calculator can divide", function() {
    equal(calculate(1,1,"/"), 1);
});

test("verifies that calculator can handle divide by zero error", function() {
    var result = calculate(1,0,"/");
    equal(result, "error");
    equal($('#validation').text(), 'Attempt to divide by zero');
});

test("verifies that calculator can handle invalid number in first argument", function() {
    calculate("invalid input",1,"+");
    equal($('#validation').text(), "Invalid input (invalid input)");
});

test("verifies that calculator can handle invalid number in second argument", function() {
    calculate(1,"invalid input","+");
    equal($('#validation').text(), "Invalid input (invalid input)");
});

test("verifies that calculator can handle empty inputs in first argument", function() {
    calculate("",1, "+");
    equal($('#validation').text(), "Blank input found");
});

test("verifies that calculator can handle empty inputs in second argument", function() {
    calculate(1, "", "+");
    equal($('#validation').text(), "Blank input found");
});

test("verifies that calculator can handle invalid operator", function() {
    calculate(1, 1, ":)");
    equal($('#validation').text(), "un-supported operation");
});

test("verifies that calculator can handle blank operator", function() {
    var result = calculate(1, 1, "");
    equal(result, "error");
    equal($('#validation').text(), "un-supported operation");
});

test("verifies that calculator can handle invalid operators", function() {
    var result = calculate(1, 1, ":)");
    equal(result, "error");
    equal($('#validation').text(), "un-supported operation");
});

Running the Example

In order to run our tests, you just need to open the file index_test.html and you will see something like:

Image 2

Points of Interest

Qunit is a great JavaScript testing framework, there is a lot more to learn about it and also about other great frameworks out there.

I just wanted to share some of the basic qunit stuff I have learned so far, I hope you like it.

History

  • First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)