Tuesday, January 27, 2015

Unit Testing with Jasmine and Karma

Overview:
Recently, I have been playing around with Javascript and AngularJS. Predominantly, being a backend developer, this was a good challenge.

And prior I had no extensive experience on Javascript nor AngularJS. So, I am a newbie.

However, I thought to blog some of my learnings, specially when it comes to testing the code.

This tutorial only touches the basic essence of Jasmine and Karma for testing your Javascript code.

The sample code for this project can be found here.
Prerequisites 

NodeJS installed. You can find out more at http://nodejs.org/

Step 1: Creating working directory

$ mkdir jasmine-karma-sample
$ cd jasmine-karma-sample

Step 2: Installing required node dependencies

$ npm install -g karma-cli

Above is installed as a global (-g) dependency

$ npm install phantomjs --save-dev
$ npm install karma-jasmine --save-dev
$ npm install karma-phantomjs-launcher --save-dev

Step 3: Creating Karma configuration file

You can learn more about Karma at http://karma-runner.github.io/

$ karma init

NOTE: This will prompt a series of questions and accept the defaults, and update the file as follows

// Karma configuration
// Generated on Tue Jan 27 2015 13:04:51 GMT+1100 (Tasmania Daylight Time)

module.exports = function(config) {
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
        'app/src/**/*.js',
        'app/test/**/*_spec.js'
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['progress'],


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: false,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['PhantomJS'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: true
  });
};

Step 4: Verifying the project structure

jasmine-karma-sample
   |
   |- node_modules  // this is created as a result of npm install commands
   |
   `- karma.config.js  // this is created as a result of karma init command

Step 5: Writing Jasmine spec

jasmine-karma-sample/app/test/basic_spec.js

'use strict';


describe('Basic Jasmine Syntax', function() {

    describe('Some simple Jasmine constructs', function() {
        it('expects 2 to be 2', function() {
            expect(2).toBe(2);
        });

        it('expects Foo and Bar are not equal', function() {
            expect('Foo').not.toEqual('Bar');
        })

        it('checks if variable is defined', function() {
            var variable = 1;
            expect(variable).toBeDefined();
        })

        it('checks if variable is undefined', function() {
            var variable;
            expect(variable).toBeUndefined();
        })
    });

    describe('an Array', function() {
        var theArray;

        beforeEach(function() {
            theArray = ['Karma', 'Jasmine'];
        });

        it('checks if the array is not empty', function() {
            expect(theArray).toContain('Karma', 'Jasmine');
        });

        it('adds elements to the array', function() {
            theArray.push('PhantomJS');
            expect(theArray).toEqual(['Karma', 'Jasmine', 'PhantomJS']);
        });

        it('removes elements from the array', function() {
            theArray.pop('Jasmine');
            expect(theArray).toEqual(['Karma']);
        })
    });

});


This file contains the symmetric of a Jasmine specification. You can learn more about Jasmine at http://jasmine.github.io/

Step 6: Running the Jasmine tests

$ karma start karma.config.js

You'll see all your tests being run and their results.

Step 6: Writing more Jasmine tests

jasmine-karma-sample/app/test/calculator_spec.js

'use strict';


describe('a Calculator', function () {

    var theCalculator = org_namespace.Calculator;

    beforeEach(function () {
        theCalculator.reset();
    });

    it('checks if the calculator has been reset', function () {
        expect(theCalculator.result).toBe(0);
    });

    it('adds two integers', function () {
        theCalculator.add(10, -30);
        expect(theCalculator.result).toBe(-20);
    })

    it('multiplies two integers', function () {
        theCalculator.multiply(10, 5);
        expect(theCalculator.result).toBe(50);
    })
});
 
jasmine-karma-sample/app/src/calculator_spec.js

'use strict';

var org_namespace = {};
org_namespace.Calculator = {
    result: 0,
    add: function (x, y) {
        this.result = x + y;
    },

    multiply: function (x, y) {
        this.result = x * y;
    },

    reset: function () {
        this.result = 0;
    }
};

Summary:
In this article, we looked at how to test Javascript code using Jasmine. You can find the sample code for this post here.

No comments:

Post a Comment