JavaScript Unit Testing and Code Coverage

January 21, 2016    testing javascript unit test

b1cda5a7a4e429cbb4df3f5c0d27c2b9

In my last blog post A Web Developer’s Transition From School to the Workplace I wrote that as a web developer, you should never stop learning and growing. I joined a new company a bit over a year ago and in the past year I have learned a lot, specifically about unit testing code. This is because on our projects, unit tests are required for a user story to be closed.

At previous companies I have worked at, unit tests were never enforced for JavaScript code. According to this recent survey, 59.66% of respondents do not use a tool to test their JavaScript.

A unit test primarily focuses on a single unit of code. For example, a function can be a unit of code that can be tested. Unit tests should be small and easy to run. They should also be independent from any dependencies which means no network or database access. Mock data objects are instead used for any code that requires data.

Importance of Unit Testing

  • Unit tests enables you and your team to make changes to the code without breaking the existing application because the tests fail if something is broken.
  • Saves a lot of time since you will know your code is broken when the tests fail instead of manually testing the application.
  • Encourages modular code and reduces code complexity because it enforces you to write smaller and testable blocks of code.
  • Easier in the long run when you or a new developer makes changes or refactors the code in the future.
  • Helps you better understand the design of the code that is being tested.
  • Reduces the need for documentation and long comments because you are able to see all of the conditions and results expected from that unit of code.
  • Gives a nice visual feedback (green for pass and red for fail) which tells your brain whether you are doing something right or wrong.

Examples

AngularJS Unit Testing

describe('Home Page', function () {
    var controller;

    beforeEach(module('app.home'));

    beforeEach(inject(function ($controller) {
        controller = $controller;

        controller = $controller('HomeController', {});
    }));

    it('should set someVar to blue', function() {
        expect(controller.someVar).toEqual('blue');
    });

    it('should set someList to one, two, three', function() {
        expect(controller.someList).toEqual(['one', 'two', 'three']);
    });

    describe('Click Button', function () {
        it('should show alert message when clicked', function() {
            spyOn(window, 'alert');
            controller.someFunctionUsedByTheHomePage();
            expect(window.alert).toHaveBeenCalledWith('Congratulations');
        });
    });
});

Sails.js (Node.js) Unit Testing

var HelloController = require('../../api/controllers/HelloWorldController'),
    assert = require('chai').assert,
    request = require('supertest'),
    url = 'http://localhost:1337';

describe('The Hello Controller', function() {
    var Sails = require('sails'),
        sails;

    before(function(done) {
      Sails.lift({}, function(err, server) {
        sails = server;
        if (err) return done(err);
            done(err, sails);
        });
    });

    after(function(done) {
        Sails.lower(done);
    });

    describe('GET /helloworld', function() {
        it('should return hello world message', function(done) {
            request(url)
                .get('/HelloWorld')
                .end(function(err, res) {
                    if (err) {
                        throw err;
                    }

                    assert(res.status, 200);
                    assert(res.text, 'Hello World');
                    done();
                });
        });
    });
});

Code Coverage

A way to measure the amount of code that is actually being tested is to use a code coverage tool, a nice tool to use is Istanbul. It is a good approach to identify if you have properly tested a line of code.

Using a coverage tool provides you a friendly visual report.

Screen Shot 2016-01-21 at 10.05.51 AM