netdance / Mocha-AMD-Backbone-example

Example using Backbone with AMD, and Mocha for testing

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mocha AMD Backbone example

An example using Backbone in combination with Mocha.

THIS CODE IS NOT YET EVEN FULLY STARTED, AND SHOULD NOT BE RELIED ON IN ANY WAY

Usage

Mocha AMD example has one usage: to demonstrate how to use a bunch of awesome javascript libraries in combination.

Why is this helpful? It's pretty tricky to figure it out on your own (or at least it was for me). So, hopefully, this will be of some help to someone struggling to put this group of libraries together.

The Mocha AMD example is purposefully lightweight. There's no example demonstrating how to tie in Backbone, for instance, but if you're able to set these tests up, taking it from there should be pretty simple.

Configuration Examples

Gruntfile Configuration Example

Mocha Configuration for Your Gruntfile:

module.exports = function(grunt) {
  grunt.initConfig({
    mocha: {
      // Test all files ending in .html anywhere inside the test directory.
      browser: ['test/**/*.html'],
      options: {
        reporter: 'Spec', 
        run: true
      }   
    }
  });
  
  grunt.loadNpmTasks('grunt-mocha');
  
  grunt.registerTask('test', ['mocha']);
};

In this example, tests are stored in a test directory relative to the Gruntfile.

package.json Configuration

This example uses Grunt, as well as it's mocha support -- and is, therefore, dependent upon them being installed.

It's good practice to put your projects dependencies inside a package.json file, and also check them in to your source control. But for this project, we don't, since you can just download them again on checkout with npm install command. (This is the difference between an example project and a production system.)

This package.json file fetches grunt, grunt-cli (which lets you type grunt on the command line), and grunt-mocha, which allows you to use the mocha section inside your grunt file.

{
  "name": "Mocha-AMD-example",
  "version": "0.1.0",
  "dependencies": {
  },
  "devDependencies": {
    "grunt": "~0.4.2",
    "grunt-cli": "~0.1.11",
    "grunt-mocha": "~0.4.7",
    "bower": "~1.2.8"
  }
}

bower.json Configuration

The following is a small subset of bower.json file. Like the package.json file, it details the dependencies of your project. While the package.json file lists dependencies for Grunt, the bower.json file lists dependencies that you'll consume in your browser. For this example, that includes testing libraries.

Since our tests include chai, mocha, sinonjs and squire, we include them here. The app itself needs requirejs, so that's in the separate production dependencies section.

Like in package.json, you should check these libraries in to your source control, so your build isn't dependent on github being up, but again, for our example, we let you fetch it yourself via bower install.

  "devDependencies": {
    "chai": "~1.8.1",
    "mocha": "~1.15.1",
    "sinonjs": "~1.7.3",
    "squire": "*"
  },
  "dependencies": {
    "requirejs": "~2.1.9"
  }

RequireJS Config File Example

There are two different RequireJS config files in this example. The first is for the source:

require.config({
  'paths': {
    'add-one': 'add-one',
    'times-six': 'times-six',
    'arithmetic': 'arithmetic'
  }
});

The second is for the test code:

require.config({
  'paths': {
    'squire': '../bower_components/squire/src/Squire'
  }
});

For the tests, we first include the source config, then the test config. That way, when we run our "application", it's free of test dependencies.

In this example, there's three JS files to the "application". With this config file, the add-one.js code can be accessed like so:

require(['add-one'], function(AddOne) {
  var three = AddOne.addOne(2);
});

Testing Example

Unit testing with Mocha and Chai is dead simple.

In this example, I'm testing an addOne function. The code looks something like:

// Describe allows you to create a group of tests.
describe('addOne Test', function() {
  // it() is the test.
  it('Should be 2.', function() {
    // Chai provides a nice interface for assertions.
    chai.assert.equal(AddOne.addOne(1), 2);
  });
});

An Example of Testing an Asynchronous RequireJS Callback:

describe('addOne Test', function() {
 it('Should be 2.', function(done) {
   require([
     'add-one'
   ], function(AddOne) {
     chai.assert.equal(AddOne.addOne(1), 2);
     done();
   });
 });
});

Notice the addition of done as a parameter to it(). done allows your tests to occurr asynchronoulsy, but it requires that it be envoked to end the test -- notice the call to done(); at the end of the test. You can also wrap the whole test with the require - then you won't need to call 'done()'.

require([
     'add-one'
], function(AddOne) {
  describe('addOne Test', function() {
      it('Should be 2.', function(done) {
        chai.assert.equal(AddOne.addOne(1), 2);
      });
  });
});

A Stubbing Example with Sinon

describe('addOne Test', function() {
  it('Should be 42; stubbed by sinon.', function() {
    AddOne.addOne = sinon.stub().returns(42);
    chai.assert.equal(AddOne.addOne(1), 42);
  });
});

sinon.stub().returns() allows you to override a function and force it to return whatever you want. In this example, it returns 42.

A Stubbing example with Squire

require([
  'squire'
  ], function(Squire) {
  var injector = new Squire();
  describe('arithmetic Exemplary Test 2', function() {
    it('Should be 42. mocked add-one', function(done) {
      injector.mock('add-one', function() { 
        return {
          addOne: function(x) {
            return x+6;  // add-one will now always add 6
          }
        }
      }).require(['arithmetic'],function(Arithmetic){
        chai.assert.equal(Arithmetic.answer, 42);
        done();
      });
    });
  });
);

Sometimes, you need to stub out required dependencies. Squire offers one way to do that. First, use require to load squire, initialize an injector instance, then use that to stub out and require (or just require without a stub) any dependencies. In this example, the 'add-one' dependency of the 'arithmetic' module is replaced with a dummy function which just returns a constant number.

Application Structure

The point of tying all of these libraries together is to help assuage the pain of working with large JavaScript projects. Feel free to organize you're project however you like, but it's probably worth some of your time to think about the structure.

For this simple example, the path directory is:

`-repo/          # Repository of all code.
  `-src/         # Directory containing the source code of the application
  `-test/        # Directory containing the test code.
  `-bower.json   # front end library configuration file
  `-Gruntfile.js # Grunt configuration file.
  `-license.txt  # License to hack.
  `-package.json # package configuratoin file.
  `-README.md    # This lovely file.

Dependencies

Node & npm bower

If you don't have Node or npm installed, the above links should be easy to follow. Bower installs easily with npm.

For easiest use, you may wish to also install grunt's command line interface, as well as bower, into a globally usable directory in your path, such as /usr/local/bin.

On a Unix (or Mac) system, you'd do this by

sudo npm -g install grunt-cli
sudo npm -g install bower

Getting Started

1: Clone the repository.

git clone https://github.com/netdance/Mocha-AMD-example.git

(or just use Github's awesome GUI tool)

2: Inside the repository, install the javascript dependencies.

npm install

then

./node_modules//bower/bin/bower install

or, if you've installed bower globally, just bower install

3: Run the tests!

./node_modules/grunt-cli/bin/grunt test

again, if you've installed grunt-cli globally, just grunt

If you don't see something like:

Running "mocha:browser" (mocha) task
Testing: test/example.html


  addOne Exemplary Tests
    ✓ Should be 2. 
    ✓ Should be 42; Sinon stub. 
    ✓ Should be 2 (again); unstubbed. 

(... more tests run here)

  11 passing (3ms)

>> 11 passed! (0.00s)

Done, without errors.

you messed something up (somehow).

Other Resources

  • grunt-mocha - Most helpful resource that I found while trying to tie these libraries together.
  • Grunt Guide - Grunt's documentation (in case you have any troubles with grunt or grunt-cli).
  • [Sinon Examples](http://sinonjs.org/docs/ "Sinon Documentation - "Mocks and Stubs and Spies, oh my!") - Use cases for Sinon (and why you might want to consider using it, if you're not already).
  • Mocha Examples - Unit tests example with Mocha (and why you might want to consider it, if you're using something else).
  • RequireJS / Backbone Configuration - Not the best example, but...

License

Mocha-AMD-example is free--as in BSD. Hack your heart out, hackers.

This code was origninally started in cuzzo/grunt-requirejs-mocha-chai-sinon-example - and I'm deeply indebted to him for the clarity of his example. Hopefully I didn't complicate it too much.

About

Example using Backbone with AMD, and Mocha for testing

License:Other


Languages

Language:JavaScript 100.0%