Testing JavaScript with Jasmine
Being a quick guide on testing JavaScript code with a testing framework called Jasmine.
Now that my JavaScript usage has progressed beyond the “Just enough to use jQuery” level, I decided it was time to start testing it. (Yes, I should have been doing it before, but better late than never, right?) I am writing a small module called Tolmey for dowloading mapping tiles from a latitudei and a longitude, and needed to test it.
Why Test Your Code?
- Your code will be better. Code that is easy to test is generally easy to use. Code that is hard to test is brittle and harder to use. Testing encourages you to think about how someone will actually use the API you are making, not just if it is correct or not.
- You know it is correct.
- If you have good enough test coverage, you know what is broken when things break. A failing test gives you a reproducible error case, which makes debugging and fixing the bug much easier. You can refactor with confidence instead of cowering in fear of breaking something irreparably.
- ? ? ?
- Profit
How To Test
Jasmine is my JavaScript testing framework of choice. Jasmine. It is modeled after RSpec, a testing framework for Ruby.
Jasmine doesn’t assume you are using the DOM. It can handle testing client-side code, but it is not tied to it. That means you can use the same testing setup for your client and server-side code, which is nice.
Initial Setup
NOTE: If you already know how to develop npm modules, this will be mostly review for you. Sorry, but if you want to follow along with the actual testing part, you need a project that looks like mine.
-
There are several ways to test your code with Jasmine. I am used to just running specs from a command line tool, so the easiest way for me was to install jasmine-node. It require NPM and Node.js, so make sure you have those installed. Once you do, run:
npm install -g jasmine-node
-
Now that jasmine-nodes is installed, we need to make sure our project we want to test is set up for it. I will walk through creating and testing a really simple project that provides a function to add “in the bathtub” to strings.
mkdir bathtub && cd bathtub
Save this code as
package.json
inside the folder we created:{ "name": "bathtub", "description": "All in the bathtub, all the time.", "version": "0.0.1", "author": "Jamison Dance <[email protected]> (http://jamisondance.com)", "main": "./bathtub.js", "keywords": ["bathtub", "awesome"] }
I don’t want to give a full overview of what the
package.json
file does, but its basic purpose it to tell JavaScript package managers about your code. -
Save this file as
bathtub.js
in the same directory:(function () { "use strict"; function inTheBathtub(string) { return string + " in the bathtub."; } module.exports = inTheBathtub; }());
This is our JavaScript project. It is a simple function that appends ” in the bathtub” to a string that is passed in to it. The
module.exports = inTheBathtub;
line lets npm and Ender know that when someone typesrequire('bathtub')
, it should return our function. -
Now run
npm link
to create a symbolic link between our project and the systemnode_package
directory. This tells Node.js, and by extension jasmine-node, where to find the code for the bathtub module.
Creating And Running Tests
-
Create a directory to hold your tests. I like to call mine
spec
:mkdir spec && cd spec
-
Create a file named
bathtub_spec.js
in yourspec
directory with the following code://Load our function var bathtub = require('bathtub'); describe('bathtub', function () { it("should append \"in the bathtub\" to a string", function () { var input = "Nothing delights me more than the fine scent of Jarlsberg cheese"; expect(bathtub(input)).toEqual(input + " in the jacuzzi."); }); });
Jasmine lets you write tests that read something like English. We are describing some functionality of our
bathtub
function.it()
is the actual test that we want to run. We expect our function to append ” in the jacuzzi.” to a string we pass in to it. -
Run our spec:
cd .. jasmine-node spec/
If you followed the code exactly, you should see a notice telling you that the test failed! This is what my output looks like:
Started F bathtub it should append "in the bathtub" to a string Error: Expected 'Nothing delights me more than the fine scent of Jarlsberg cheese in the bathtub.' to equal 'Nothing delights me more than the fine scent of Jarlsberg cheese in the jacuzzi.'. at [object Object].<anonymous> (/Users/jergason/bathtub/spec/bathtub_spec.js:6:28) Finished in 0.003 seconds 1 test, 1 assertion, 1 failure
Looks like we have a bug somewhere. If you look at the spec, notice we are expecting “jacuzzi”, not bathtub. Whoops! Change the offending word of the spec to “bathtub” and run it again. You should see a message telling you the specs passed.
Further Exploration
This simple project was more to set up the environment than to
demonstrate all the functionality of Jasmine. The toEqual()
method is
a matcher. There are many more that let you test all kinds of things,
and you can add your own if you don’t find one that suits you. See
https://github.com/pivotal/jasmine/wiki/Matchers
for more info about matchers.
That is all for this post. Look out for another post that gets more in depth into Jasmine and testing.