http://www.developer.com/http://www.developer.com/lang/jscript/testing-javascript-code-with-jasmine.html
JavaScript has remained a popular, if often derided, language since its very inception back in 1995. In recent years its adoption has skyrocketed as demand for standards- and cross device-compliant Web applications has soared. Such applications tend to be pretty complex projects, and appropriately developers have sought to employ sound testing approaches which ensure the code is operating as expected. While manual testing has its place, automated testing strategies can help to ensure maximum and prolonged coverage of code throughout the project lifetime. Server-side developers have long experienced the benefits of automated testing solutions, taking advantage of testing frameworks such as RSpec for Ruby, PHPUnit for PHP, and JUnit for Java. If you fall into this crowd but are starting to spend more time with JavaScript, chances are you're fretting over how to apply similar techniques on the client (or or server!) side. Not to worry, as several interesting JavaScript testing frameworks exist, perhaps chief among them Jasmine, a popular open source behavior-driven development framework. Unlike many of the JavaScript testing frameworks which preceded it, Jasmine is dependency-free, allowing you to run Jasmine without further configuration in any environment which runs JavaScript. While you're able to install Jasmine by downloading it from the project page (or more conveniently by cloning it), I suggest installing it as a Ruby gem as the gem offers a few additional convenience features not available via the download. Don't worry if your JavaScript project doesn't otherwise involve Ruby or Rails, because the gem can be used in conjunction with any language! Begin by installing the gem: Once installed, create and enter a new directory which we'll use as the basis for exploring Jasmine's capabilities, and then execute the following two commands: To make sure the Jasmine server is properly running, head over to If you click the These specs correspond to the Let's use this class as the basis for exploring Jasmine's capabilities. Incidentally, if you're not familiar with JavaScript's prototype-based OOP design, see the article, Object-Oriented JavaScript Demystified. The example specs which are used to validate the Begin by creating a file named Save the file and refresh the browser. You'll see that the So what does this spec accomplish? The spec starts by defining the expected behavior in plain English. In our case, we expect the hello world spec to pass. In order to test the behavior, the Change one of the compared values to So far, so good. Let's revise the When executed, the Refresh the browser and you'll see this spec does indeed pass. But we should also ensure that the A spec suite is organized in a manner such that it is obvious a particular group of specs are intended to thoroughly test a particular behavior. This is done by nesting the related specs inside the Refresh the browser and you'll see that not only have both tests passed, but they have also been grouped in such a way that it is apparent they are intended to test a specific behavior. But the specs aren't DRY, which will inevitably come back to bite us at one point. Use the Of the various BDD frameworks I've used over the years, Jasmine is by far my favorite, offering an incredibly intuitive and natural testing approach. Hopefully this article helped to illustrate some of the features I find so appealing. Are you using Jasmine or other JavaScript testing frameworks? Tell us about your experiences in the comments!
Testing JavaScript Code with Jasmine
August 9, 2011
Installing Jasmine
$ gem install jasmine$ jasmine init
Jasmine has been installed with example specs.
...
$ rake jasmine
(in /var/www)
your tests are here:
http://localhost:8888/http://localhost:8888/. You should see the same output as that presented in Figure 1.
Click here for larger image
Figure 1. The Jasmine Spec SuiteRunning the Example Specs
passed checkbox located at the top right of the page presented in Figure 1, you'll be provided with more details about the five sample tests (known as specs in Jasmine parlance) provided with the Jasmine example spec suite (Figure 2).
Click here for larger image
Figure 2. Viewing the Example SpecsPlayer.js class, found in the newly created public/javascripts directory. This class is representative of a JavaScript-based music player. Here's the code:function Player() {
}
Player.prototype.play = function(song) {
this.currentlyPlayingSong = song;
this.isPlaying = true;
};
Player.prototype.pause = function() {
this.isPlaying = false;
};
Player.prototype.resume = function() {
if (this.isPlaying) {
throw new Error("song is already playing");
}
this.isPlaying = true;
};
Player.prototype.makeFavorite = function() {
this.currentlyPlayingSong.persistFavoriteStatus(true);
};Player class' behavior are found in a file named PlayerSpec.js which is located in the spec/javascripts directory. While I certainly suggest you review PlayerSpec.js as it offers a great example of how to write a proper spec suite, consider first following along with the ensuing creation of our own suite, as it will serve to introduce several concepts demonstrated in the PlayerSpec.js suite.Play2Spec.js, saving it to the spec/javascripts directory. Add the following contents to this file:describe("Play2", function() {
it('Hello world test passes', function() {
expect(true).toBe(true);
});
});Play2 suite has been added to the list of running specs (Figure 3).
Click here for larger image
Figure 3. Running Multiple Test Suitesit method accepts a callback which defines the expectation. We are simply expecting the value true to be true.it('Hello world test passes', function() {
expect(true).toBe(true);
});false and refresh the browser. You'll see that the spec fails, as depicted in Figure 4.
Click here for larger image
Figure 4. Viewing a Failed SpecPlay2 spec to put the Player class through the ringer.Testing the Player Class
Player class' play method assigns values to the currentlyPlayingSong and isPlaying properties. Let's write a test to ensure the currentlyPlayingSong property is indeed set to the proper song. The song in question is an object instantiated via the Song class (found in the public/javascripts directory) passed into the Player class' play methodit('The Player is playing the proper song', function() {
var player = new Player();
var song = new Song();
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
});isPlaying property is also set to true. You could perform the expectation test into the above spec, however perhaps breaking it out into its own spec is a better idea. When you create multiple specs intended to test one specific behavior (in our case, the behavior of the play method), you should create a suite.Creating a Spec Suite
describe() function:describe("Play2", function() {
describe("when song is being played", function() {
it('The Player knows it is playing', function() {
var player = new Player();
var song = new Song();
player.play(song);
expect(player.isPlaying).toBe(true);
});
it('The Player is playing the proper song', function() {
var player = new Player();
var song = new Song();
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
});
});
});beforeEach() function to solve this problem:describe("when song is being played", function() {
beforeEach(function() {
player = new Player();
song = new Song();
});
it('The Player knows it is playing', function() {
player.play(song);
expect(player.isPlaying).toBe(true);
});
it('The Player is playing the proper song', function() {
player.play(song);
expect(player.currentlyPlayingSong).toEqual(song);
});
});Conclusion