8. Testing with Jasmine

To me there is no greater sin than writing code that doesn’t have tests. It is my belief that testing is not an option.1 Testing is required. I feel so strongly in that statement that I practice what is known as TDD.2 TDD, or test-driven development, is a philosophy of writing code that states you should always write your tests first and your code last. By practicing TDD you can sleep well at night, knowing that your code is well tested and that should anything crop up, you can quickly and easily fix it with the comfort and knowledge that you haven’t broken anything else.

The art of TDD can be daunting; a lot of people don’t know where to begin. If you need some guidance on how to become a test-driven developer, might I recommend a little blog post written by yours truly, titled “How to Become a Test-driven Developer.”3

In this chapter I want to take a quick look at what I consider to be one of the best testing tools out there for testing JavaScript applications—Jasmine.4


Tip

Jasmine isn’t the only testing tool for JavaScript; in fact, there are quite a few. I think Jasmine is one of the nicest ones around because it emulates my favorite Ruby testing framework, RSpec.5 Other JavaScript testing frameworks to check out include QUnit,6 JsTestDriver,7 and YUI Test.8


I won’t be covering Jasmine in great detail here. You can find a number of great articles and videos on the Internet covering Jasmine in more detail. Instead, I want to show you how to use Jasmine with CoffeeScript and to give you a feel for what it can do.

Installing Jasmine

Typically, as you may remember from the beginning of this book, I don’t like to cover installation of tools in a book. The reason is pretty obvious—the instructions tend to be out of date by the time I finish typing, let alone by the time the book goes to print. The same is true here.

With that out of the way, I will point out what I consider to be the best way to install and set up Jasmine with CoffeeScript support. That would be to use the jasmine-headless-webkit9 Ruby gem. Because this is a Ruby gem it requires Ruby to be installed. It also features a few other dependencies. The link in the footnote has detailed instructions on how to get it set up.

There are ways of setting up Jasmine that aren’t as tricky. However, they don’t have native CoffeeScript support and require all sorts of precompilation of both your source files and your tests, and let’s be honest, who wants to deal with all of that?

If you don’t want to use jasmine-headless-webkit and instead use another version of Jasmine, that’s fine. For this chapter we will be using jasmine-headless-webkit, so I would recommend using that if you plan to follow along.

Setting Up Jasmine

I’m going to assume that you have installed Jasmine and are ready to go. So let’s get started.

In this chapter we are going to build a simple calculator project. It will do the basic stuff that calculators do: add, subtract, multiply, and divide. Create a new folder for the project. Inside the project folder run the following command to set up Jasmine:

> jasmine init

When you do that, Jasmine should create a bunch of new files and folders in the project directory that look something like this:

public/
  javascripts/
    Player.js
    Song.js
Rakefile
spec/
  javascripts/
    helpers/
      SpecHelper.js
    PlayerSpec.js
  support/
    jasmine.yml
    jasmine_config.rb
    jasmine_runner.rb

Jasmine throws a few example files in there to give us a feeling for how Jasmine works and to help us make sure that it has been set up and configured correctly. Let’s test that now:

> jasmine-headless-webkit -c

With any luck you should see output similar to the following:

Running Jasmine specs...
.....
PASS: 5 tests, 0 failures, 0.009 secs.

Great! We now have Jasmine up and running. Things look good. Well, everything except that awful command we have to execute on the command line whenever we want to run our tests. Let’s use what we learned in Chapter 7, “Cake and Cakefiles,” and write up a quick Cake task to help keep things simple.

First, I’ll show you the Cakefile and then I’ll explain it.

Example: (source: calc.1/Cakefile)


exec = require('child_process').exec

task "test", (options) =>
  exec "jasmine-headless-webkit -c", (error, stdout, stderr)->
    console.log stdout


Example: (source: calc.1/Cakefile.js)


(function() {
  var exec,
    _this = this;

  exec = require('child_process').exec;

  task("test", function(options) {
    return exec("jasmine-headless-webkit -c", function(error, stdout, stderr) {
      return console.log(stdout);
    });
  });

}).call(this);


Output: (source: calc.1/Cakefile)


Cakefile defines the following tasks:

cake test


This is definitely not the most complex Cakefile or Cake task you’ll ever see, but it does deserve a bit of explaining. The real magic of this Cake task is happening in the first line. In this line we import the child_process module from the Node.js10 toolset. Don’t worry if you don’t understand what it’s doing or how it works; we’ll cover importing modules a bit more in Chapter 9, “Intro to Node.js.”

What we get with the child_process module, in particular, is the exec function. The exec function lets us send commands to the console and then capture the output of that command when it finishes, which is exactly what we’re doing with our Cake task.

We’ve created a Cake task called test that sends our command, jasmine-headless-webkit -c, to the command line, where the tests are run. When the tests have finished, our callback function is executed, and the results of the tests print out to the console.

Now if you type the following in the console:

> cake test

you should see the results of the tests, just like we did earlier.

With the command line cleaned up a bit, let’s do some final configuration of our project before we dive into writing some tests.

First, we’ll clean up the project a bit and get rid of all those example files that were generated for us that we don’t want. You should delete files and directories until your project directory looks like this:

src/
Rakefile
spec/
  javascripts/
    helpers/
  support/
    jasmine.yml
    jasmine_config.rb
    jasmine_runner.rb

Okay, we are almost there. The last thing we need to do is configure the spec/javascripts/support/jasmine.yml file to give it the specifics of our project:

Example: (source: calc.2/spec/javascripts/support/jasmine.yml)


src_files:
  - "**/*.coffee"

helpers:
    - "helpers/**/*.coffee"

spec_files:
  - /**/*_spec.coffee

src_dir: "src"

spec_dir: spec/javascripts


Now we are finally ready to start looking at Jasmine code!

Introduction to Jasmine

So what does a Jasmine test look like? Let’s build a simple one and you’ll see.

In our spec directory, let’s create a new file called calculator_spec.coffee. This file is where we will build all the tests, or specs as they’re sometimes known, for our calculator. Let’s first see what our simple test will look at, and then we’ll dissect it to understand better what it’s doing.

Example: (source: calc.3/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  it "does something", ->
    expect(1 + 1).toEqual 2
    expect(1 + 1).not.toEqual 3


Example: (source: calc.3/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    return it("does something", function() {
      expect(1 + 1).toEqual(2);
      return expect(1 + 1).not.toEqual(3);
    });
  });

}).call(this);


First, we need to create what is called a “describe” block. This is where we tell Jasmine what the “noun” is that we are going to be testing. We usually describe classes or functions. In this case we want to describe the Calculator class we’re going to build. The first argument to the describe function is a string that represents the noun “Calculator.” The second argument is going to be a function that will contain all the tests associated with that noun.

Inside the callback function we give to the describe function we can define “it” blocks. An “it” block, which is just a function, is similar to the “describe” function, or block, in that it takes two arguments. The first argument is a string that represents what we plan on testing now. In this short example we want to test that the “Calculator” “does something.” The second argument is a function that contains the assertions to prove what it is we are testing.

In our “does something” test, we are asserting that 1 + 1 equals 2. We are also rather triumphantly asserting that 1 + 1 does not equal 3. We did these tests using what are called matchers; in this case we used the toEqual matcher. Matchers have one simple rule: if the matcher returns true the test passes; otherwise, the test fails.

So what does the expect function do and why do we need it? The expect function takes as its argument the statement you want to test, so for us it would be 1 + 1, and returns a special object that has the matcher functions on it. In a nutshell, it’s there to make Jasmine’s life a little easier. It also helps the readability of your tests a bit.


Tip

Jasmine ships with a handful of matchers that you can use to test almost anything. You can find a list of these matchers on the documentation11 site for Jasmine.


Unit Testing

Now that we have a basic understanding of how to write a Jasmine test, let’s flesh out what the tests are going to look like for our Calculator class. We’ll start by removing our example test and adding four describe blocks to test addition, subtraction, multiplication, and division:

Example: (source: calc.4/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  describe "#add", ->

    it "adds two numbers", ->

  describe "#subtract", ->

    it "subtracts two numbers", ->

  describe "#multiply", ->

    it "multiplies two numbers", ->

  describe "#divide", ->

    it "divides two numbers", ->


Example: (source: calc.4/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    describe("#add", function() {
      return it("adds two numbers", function() {});
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {});
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {});
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {});
    });
  });

}).call(this);


After looking at that code, you are probably wondering why there are multiple “describe” blocks under our initial “describe.” We do that because we are going to be writing tests for each of the four functions we’re going to have on our Calculator class. Each of these functions is a noun that we are going to be testing. Below each of those nouns are the “it” blocks that state what we will be testing.

We can run our tests with this:

> cake test

The output of our tests should look like this:

Running Jasmine specs...
....
PASS: 4 tests, 0 failures, 0.02 secs.


Tip

There is a # before each of the function names in our test because that is a common testing style that indicates that function is an instance-level function. If we were to describe class-level functions, we would preface the function name with . instead of #.


Our tests all pass because there is nothing inside of the “it” blocks. Let’s flesh them all out a bit:

Example: (source: calc.5/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  describe "#add", ->

    it "adds two numbers", ->
      calculator = new Calculator()
      expect(calculator.add(1, 1)).toEqual 2

  describe "#subtract", ->

    it "subtracts two numbers", ->
      calculator = new Calculator()
      expect(calculator.subtract(10, 1)).toEqual 9

  describe "#multiply", ->

    it "multiplies two numbers", ->
      calculator = new Calculator()
      expect(calculator.multiply(5, 4)).toEqual 20

  describe "#divide", ->

    it "divides two numbers", ->
      calculator = new Calculator()
      expect(calculator.divide(20, 5)).toEqual 4


Example: (source: calc.5/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    describe("#add", function() {
      return it("adds two numbers", function() {
        var calculator;
        calculator = new Calculator();
        return expect(calculator.add(1, 1)).toEqual(2);
      });
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {
        var calculator;
        calculator = new Calculator();
        return expect(calculator.subtract(10, 1)).toEqual(9);
      });
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {
        var calculator;
        calculator = new Calculator();
        return expect(calculator.multiply(5, 4)).toEqual(20);
      });
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {
        var calculator;
        calculator = new Calculator();
        return expect(calculator.divide(20, 5)).toEqual(4);
      });
    });
  });

}).call(this);


Now we’re starting to get somewhere. We have nice looking tests that describe and test the four functions we’re going to have on our Calculator class, so what happens if we run the tests?

Running Jasmine specs...
FFFF

Calculator #add adds two numbers. (../jasmine/calc.5/spec/javascripts/calculator_spec.coffee:5)
  ReferenceError: Can't find variable: Calculator in ../jasmine/calc.5/spec/javascripts/calculator_spec.coffee (line ~6)


Calculator #subtract subtracts two numbers. (../jasmine/calc.5/spec/javascripts/calculator_spec.coffee:11)
  ReferenceError: Can't find variable: Calculator in ../jasmine/calc.5/spec/javascripts/calculator_spec.coffee (line ~13)


Calculator #multiply multiplies two numbers. (../jasmine/calc.5/spec/javascripts/calculator_spec.coffee:17)
  ReferenceError: Can't find variable: Calculator in ../jasmine/calc.5/spec/javascripts/calculator_spec.coffee (line ~20)


Calculator #divide divides two numbers. (../jasmine/calc.5/spec/javascripts/calculator_spec.coffee:23)
  ReferenceError: Can't find variable: Calculator in ../jasmine/calc.5/spec/javascripts/calculator_spec.coffee (line ~27)

FAIL: 4 tests, 4 failures, 0.017 secs.

All tests are now failing, and they’re failing for a very good reason—we haven’t written our Calculator class yet! So let’s do that; it’s a pretty simple class:

Example: (source: calc.6/src/calculator.coffee)


class @Calculator

  add: (a, b) ->
    a + b

  subtract: (a, b) ->
    a - b

  multiply: (a, b) ->
    a * b

  divide: (a, b) ->
    a / b


Example: (source: calc.6/src/calculator.js)


(function() {

  this.Calculator = (function() {

    function Calculator() {}

    Calculator.prototype.add = function(a, b) {
      return a + b;
    };

    Calculator.prototype.subtract = function(a, b) {
      return a - b;
    };

    Calculator.prototype.multiply = function(a, b) {
      return a * b;
    };

    Calculator.prototype.divide = function(a, b) {
      return a / b;
    };

    return Calculator;

  })();

}).call(this);


Now when we run our tests again we should see them all passing:

Running Jasmine specs...
....
PASS: 4 tests, 0 failures, 0.021 secs.

Before and After

Our tests look pretty good now, but a lot of duplication occurs in each test. In each test we are creating a new instance of our Calculator class. Jasmine will help us clean that up a bit using the beforeEach function.


Tip

As you might guess, there is also an afterEach function. The afterEach is great for resetting databases, files, or other fixture data back to where it was before the test was run.


Let’s move the creation of an instance of the Calculator class to a beforeEach call. We do that by passing a function to the beforeEach function that will be called before each “it” block in the current “describe” block, as well as any subsequent “describe” blocks.

Example: (source: calc.7/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  beforeEach ->
    @calculator = new Calculator()

  describe "#add", ->

    it "adds two numbers", ->
      expect(@calculator.add(1, 1)).toEqual 2

  describe "#subtract", ->

    it "subtracts two numbers", ->
      expect(@calculator.subtract(10, 1)).toEqual 9

  describe "#multiply", ->

    it "multiplies two numbers", ->
      expect(@calculator.multiply(5, 4)).toEqual 20

  describe "#divide", ->

    it "divides two numbers", ->
      expect(@calculator.divide(20, 5)).toEqual 4


Example: (source: calc.7/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    beforeEach(function() {
      return this.calculator = new Calculator();
    });
    describe("#add", function() {
      return it("adds two numbers", function() {
        return expect(this.calculator.add(1, 1)).toEqual(2);
      });
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {
        return expect(this.calculator.subtract(10, 1)).toEqual(9);
      });
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {
        return expect(this.calculator.multiply(5, 4)).toEqual(20);
      });
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {
        return expect(this.calculator.divide(20, 5)).toEqual(4);
      });
    });
  });

}).call(this);



Tip

The scope of beforeEach and afterEach calls can be a bit confusing. It helps to try to think of it a bit like a waterfall. The calls trickle down from the current “describe” block scope to all “describe” blocks that are nested below. It does this for as many levels of “describe” blocks there are.


When writing beforeEach functions, it’s important to know that you can have as many as you want, and they can be at any level of your tests as you need. Let’s see this in action with our Calculator class.

Let’s add a flag to our Calculator that tells the calculator whether it should operate in scientific mode.

Example: (source: calc.8/src/calculator.coffee)


class @Calculator

  constructor: (@scientific = false)->

  add: (a, b) ->
    a + b

  subtract: (a, b) ->
    a - b

  multiply: (a, b) ->
    a * b

  divide: (a, b) ->
    a / b


Example: (source: calc.8/src/calculator.js)


(function() {

  this.Calculator = (function() {

    function Calculator(scientific) {
      this.scientific = scientific != null ? scientific : false;
    }

    Calculator.prototype.add = function(a, b) {
      return a + b;
    };

    Calculator.prototype.subtract = function(a, b) {
      return a - b;
    };

    Calculator.prototype.multiply = function(a, b) {
      return a * b;
    };

    Calculator.prototype.divide = function(a, b) {
      return a / b;
    };

    return Calculator;

  })();

}).call(this);


Next, let’s add a test that asserts that its default state is not scientific mode:

Example: (source: calc.8/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  beforeEach ->
    @calculator = new Calculator()

  it "is not in scientific mode by default", ->
    expect(@calculator.scientific).toBeFalse()

  describe "#add", ->

    it "adds two numbers", ->
      expect(@calculator.add(1, 1)).toEqual 2

  describe "#subtract", ->

    it "subtracts two numbers", ->
      expect(@calculator.subtract(10, 1)).toEqual 9

  describe "#multiply", ->

    it "multiplies two numbers", ->
      expect(@calculator.multiply(5, 4)).toEqual 20

  describe "#divide", ->

    it "divides two numbers", ->
      expect(@calculator.divide(20, 5)).toEqual 4


Example: (source: calc.8/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    beforeEach(function() {
      return this.calculator = new Calculator();
    });
    it("is not in scientific mode by default", function() {
      return expect(this.calculator.scientific).toBeFalse();
    });
    describe("#add", function() {
      return it("adds two numbers", function() {
        return expect(this.calculator.add(1, 1)).toEqual(2);
      });
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {
        return expect(this.calculator.subtract(10, 1)).toEqual(9);
      });
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {
        return expect(this.calculator.multiply(5, 4)).toEqual(20);
      });
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {
        return expect(this.calculator.divide(20, 5)).toEqual(4);
      });
    });
  });

}).call(this);

Running Jasmine specs...
....
PASS: 5 tests, 0 failures, 0.021 secs.


Now we’ll write another “describe” block to describe our Calculator class when it’s in scientific mode and we’ll add a beforeEach call in that describe block to create a new Calculator that is in scientific mode. Let’s also write a test to assert that when we tell it to be in scientific mode, it actually is:

Example: (source: calc.9/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  beforeEach ->
    @calculator = new Calculator()

  it "is not in scientific mode by default", ->
    expect(@calculator.scientific).toBeFalse()

  describe "scientific mode", ->

    beforeEach ->
      @calculator = new Calculator(true)
    it "is in scientific mode when set", ->
      expect(@calculator.scientific).toBeTruth()

  describe "#add", ->

    it "adds two numbers", ->
      expect(@calculator.add(1, 1)).toEqual 2

  describe "#subtract", ->

    it "subtracts two numbers", ->
      expect(@calculator.subtract(10, 1)).toEqual 9

  describe "#multiply", ->

    it "multiplies two numbers", ->
      expect(@calculator.multiply(5, 4)).toEqual 20

  describe "#divide", ->

    it "divides two numbers", ->
      expect(@calculator.divide(20, 5)).toEqual 4


Example: (source: calc.9/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    beforeEach(function() {
      return this.calculator = new Calculator();
    });
    it("is not in scientific mode by default", function() {
      return expect(this.calculator.scientific).toBeFalse();
    });
    describe("scientific mode", function() {
      beforeEach(function() {
        return this.calculator = new Calculator(true);
      });
      return it("is in scientific mode when set", function() {
        return expect(this.calculator.scientific).toBeTruth();
      });
    });
    describe("#add", function() {
      return it("adds two numbers", function() {
        return expect(this.calculator.add(1, 1)).toEqual(2);
      });
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {
        return expect(this.calculator.subtract(10, 1)).toEqual(9);
      });
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {
        return expect(this.calculator.multiply(5, 4)).toEqual(20);
      });
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {
        return expect(this.calculator.divide(20, 5)).toEqual(4);
      });
    });
  });

}).call(this);

Running Jasmine specs...
......
PASS: 6 tests, 0 failures, 0.017 secs.


Custom Matchers

Before we wrap up the development of our Calculator class, we can clean up our tests a bit more by using a custom matcher to test whether the calculator in question is in scientific mode. Jasmine provides a nice, simple way of letting us define our own matchers.

In our spec/javascripts/helpers directory, let’s create a file called to_be_scientific.coffee.


Tip

The names of the files in the spec/javascripts/helpers directory don’t really matter, but I like to make sure they’re fairly descriptive. Using the name of the matcher we’re going to write in that file is a great way to easily find it later when you need to make changes to it.


Let’s add the following to that file:

Example: (source: calc.10/spec/javascripts/helpers/to_be_scientific.coffee)


beforeEach ->
  @addMatchers
    toBeScientific: ->
      @actual.scientific is true


Example: (source: calc.10/spec/javascripts/helpers/to_be_scientific.js)


(function() {

  beforeEach(function() {
    return this.addMatchers({
      toBeScientific: function() {
        return this.actual.scientific === true;
      }
    });
  });

}).call(this);



Tip

Custom matchers don’t need to be placed into their own files. You could define them all in one helper file. I like to write one per file. I find it makes my code base a littler cleaner and saner. You can also write one-off matchers in a “describe” block for a particular test should the whim strike you.


To write our custom matcher, the first thing we need to do is add a beforeEach call that will get called before every test in our entire test suite. Inside of that beforeEach call we want to call the built-in Jasmine function, addMatchers, that does just what its name says. It takes an object that contains the names of the matchers you want to add and the function that represents each of those custom matchers. It is important that the custom matcher returns either true or false as the result. Remember earlier in the chapter when I said that in Jasmine if an assertion returns true the test passes; otherwise, the test fails? This is where you define that behavior.

In our matcher, toBeScientific, we are going to assert whether the Calculator instance we are testing has the scientific flag set on it and return true or false based on that flag.

With our custom matcher in place, we can update our tests to use it like so:

Example: (source: calc.10/spec/javascripts/calculator_spec.coffee)


describe "Calculator", ->

  beforeEach ->
    @calculator = new Calculator()

  it "is not in scientific mode by default", ->
    expect(@calculator).not.toBeScientific()

  describe "scientific mode", ->
    beforeEach ->
      @calculator = new Calculator(true)

    it "is in scientific mode when set", ->
      expect(@calculator).toBeScientific()

  describe "#add", ->

    it "adds two numbers", ->
      expect(@calculator.add(1, 1)).toEqual 2

  describe "#subtract", ->

    it "subtracts two numbers", ->
      expect(@calculator.subtract(10, 1)).toEqual 9

  describe "#multiply", ->

    it "multiplies two numbers", ->
      expect(@calculator.multiply(5, 4)).toEqual 20

  describe "#divide", ->

    it "divides two numbers", ->
      expect(@calculator.divide(20, 5)).toEqual 4


Example: (source: calc.10/spec/javascripts/calculator_spec.js)


(function() {

  describe("Calculator", function() {
    beforeEach(function() {
      return this.calculator = new Calculator();
    });
    it("is not in scientific mode by default", function() {
      return expect(this.calculator).not.toBeScientific();
    });
    describe("scientific mode", function() {
      beforeEach(function() {
        return this.calculator = new Calculator(true);
      });
      return it("is in scientific mode when set", function() {
        return expect(this.calculator).toBeScientific();
      });
    });
    describe("#add", function() {
      return it("adds two numbers", function() {
        return expect(this.calculator.add(1, 1)).toEqual(2);
      });
    });
    describe("#subtract", function() {
      return it("subtracts two numbers", function() {
        return expect(this.calculator.subtract(10, 1)).toEqual(9);
      });
    });
    describe("#multiply", function() {
      return it("multiplies two numbers", function() {
        return expect(this.calculator.multiply(5, 4)).toEqual(20);
      });
    });
    return describe("#divide", function() {
      return it("divides two numbers", function() {
        return expect(this.calculator.divide(20, 5)).toEqual(4);
      });
    });
  });

}).call(this);


See how much cleaner that looks? Our custom matcher is pretty simple, but we could easily put a lot more logic in there to clean up several lines of code. For example, if our Calculator class had a GUI, we could test in our toBeScientific matcher that the scientific flag was set and the GUI keyboard had switched to a scientific keyboard instead of the standard one.

Wrapping Up

There you have it—a very quick and dirty whirlwind tour of the Jasmine test framework. In this chapter we talked a bit about why testing is important and how test-driven development can make your life a little bit nicer. I hope that I was able to show you that TDD is easy to do and can be worthwhile.

We talked briefly about a few of the ways to install Jasmine, as well as how to configure it for the way we want to work, in particular using Jasmine with CoffeeScript. After we had Jasmine set up and running, we looked at what makes up a Jasmine test.

Next we defined our tests for our Calculator class and saw them all fail because we had yet to write our implementation of the class itself. After we wrote the implementation, we saw our tests all pass.

Finally we did several iterations of our specs and learned how to use beforeEach hooks and how to write custom matchers that are more expressive for our code base.

I hope you enjoyed this quick tour of Jasmine. There are plenty of third-party libraries that can help you to write better tests, including ones that help you test your UI elements effectively. A quick search of GitHub12 will help you find some great little libraries that inspire your tests.

One last thing before I end this chapter: I want you to promise me right here and now that you will write tests for all of your code, whether that code is written in CoffeeScript, JavaScript, Java, ColdFusion, or Cobalt. Hold up your hand and say the following oath:

"
  I solemnly swear to test all of my code.
  I will not test just part of my code, but rather all of it.
  I understand that failure to test my code
  will result in Mark finding me and beating me with my own shoes.
  I do this, not just for me,
  but for all developers who have to work with my code base.
  I also pledge to make other developers take this pledge.
  Should they refuse to take this pledge I will tell Mark
  and he will beat them with their own shoes.
  Viva La Tests!
"

Congratulations. Now go forth and test!

Notes

1. http://www.metabates.com/2010/07/01/testing-is-not-an-option/

2. http://en.wikipedia.org/wiki/Test-driven_development

3. http://www.metabates.com/2010/10/12/how-to-become-a-test-driven-developer/

4. http://pivotal.github.com/jasmine/

5. https://github.com/rspec/rspec

6. http://docs.jquery.com/QUnit

7. http://code.google.com/p/js-test-driver/

8. http://yuilibrary.com/yui/docs/test/

9. http://johnbintz.github.com/jasmine-headless-webkit/

10. http://nodejs.org

11. https://github.com/pivotal/jasmine/wiki/Matchers

12. http://github.com

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.79.176