Testing Public and Private Functions in JavaScript using Jasmine and Chutzpah

Introduction

There is a big debate among the online community about how to test private functions in a module when we have only access to public functions from it. This article explains about JavaScript testing using module pattern approach. It is useful if you want to test private functions.

Using the Code

Basically, this article has three sections, HTML, JavaScript and testing.

HTML

HTML has simple controls that take two inputs and four buttons that calculate simple calculations such as Add, Subtract, Multiple and Divide.

User can enter desired numeric inputs and user can click on desired buttons to get the calculated output.Hide   Shrink 

@{
    ViewBag.Title = "Home Page";
}
http://~/Scripts/jquery-1.8.2.js
http://~/Scripts/publicmodule.js
http://~/Scripts/privatemodule.js
<h2>Index</h2>


<span id="firstNumberSpan" hidden="true">First Number:</span>
<input type="text" id="firstNumber" hidden="true"/>
<br/>
<span id="secondNumberSpan" hidden="true">Second Number:</span>
<input type="text" id="secondNumber" hidden="true"/>
<br/>
<input id="addBtn" type="button" title="Add" 

value="Add" hidden="true" class="click"/>
<input id="substractBtn" type="button" title="Substract" 

value="Substract" hidden="true" class="click"/>
<input id="multiplyBtn" type="button" title="Multiply" 

value="Multiply" hidden="true" class="click"/>
<input id="divideBtn" type="button" title="Divide" 

value="Divide" hidden="true" class="click"/>

<br/>
Result:
<label id="result">0</label>


    publicModule.Init();
 

JavaScript

JavaScript contains two modules:

  1. Public module, which will interact with HTML for all the display logic sides
  2. Private module, which will contain all the logic for calculations, which will return only the required output

By having private module, we can write tests using jasmine and see what they are returning. By this, we know that they will be returns. Here, we will write all the happy path and sad path tests so that it does not break.

In public module, it will manage all the UI related logic and we can write test to check the behavior of the browser.

Public Module
var publicModule = (function ($) {
    //Public function
    var init = function() {
        $("#firstNumber").show();
        $("#firstNumberSpan").show();
        $("#secondNumber").show();
        $("#secondNumberSpan").show();
        $("#addBtn").show();
        $("#substractBtn").show();
        $("#multiplyBtn").show();
        $("#divideBtn").show();
        attachEvents();
    };

    var attachEvents = function () {
        $(".click").click(function () {
            var firstNumber = $("#firstNumber").val();
            var secondNumber = $("#secondNumber").val();
            var result = privateModule.Calculate(this.id, parseInt(firstNumber), parseInt(secondNumber)); //Private function
            $("#result").html(result);
        });
    };

    var api = {
        Init: init, //Public function
    };
    return api;

}(jQuery));
Private Module
/*
All functions in private module will be public
*/
var privateModule = (function ($) {
    var add1 = function (first, second) {
        return first + second;
    };

    var substract1 = function (first, second) {
        return  first - second;
    };

    var multiple1 = function (first, second) {
        return first * second;
    };
    
    var divide1 = function (first, second) {
        return first / second;
    };

    var calculate = function(control, first, second) {
        var result = 0;
        switch (control) {
        case "addBtn":
            result = add1(first, second);
            break;
        case "substractBtn":
            result = substract1(first, second);
            break;
        case "multiplyBtn":
            result = multiple1(first, second);
            break;
        case "divideBtn":
            result = divide1(first, second);
            break;
        default:
        }
        return result;
    };

    var api = {
        Add: add1,
        Substract: substract1,
        Multiply: multiple1,
        Divide: divide1,
        Calculate: calculate
    };
    return api;

}(jQuery));

Testing

I used Jasmine and chutzpah for testing this modules.

Public Module Testing
/// <reference path="Scripts/jquery-1.8.2.js" />
/// <reference path="Scripts/jasmine.js" />
/// <reference path="Scripts/publicmodule.js" />
/// <reference path="Scripts/privatemodule.js" />

describe("public tests:", function () {
        var pathViews = 'Views/Home/Index.cshtml';
    
        function getMarkup(path) {
            var sResult = null;
            $.ajax({
                type: "GET",
                async: false,
                url: path,
                dataType: "text",
                success: function (result, s, x) {
                    sResult = result;
                },
                error: function (result) {
                    console.log("getMarkup failed to load");
                }
            });
            return sResult;
        }
    
        var htmlMarkup = getMarkup(pathViews);

    it("1 load page", function() {
        $("body").html(htmlMarkup);
        publicModule.Init();
    });

    it("2 should be 3 on adding 1 and 2", function () {
        $("#firstNumber").val(1);
        $("#secondNumber").val(2);
        $("#addBtn").click();
        var result = $("#result").html();
        expect(result).toEqual('3');
    });
    
    it("3 should be -1 on substract 1 and 2", function () {
        $("#substractBtn").click();
        var result = $("#result").html();
        expect(result).toEqual('-1');
    });

    it("4 should be 2 on multiply 1 and 2", function () {
        $("#multiplyBtn").click();
        var result = $("#result").html();
        expect(result).toEqual('2');
    });
    
    it("5 should be 2 on divide 1 and 2", function () {
        $("#divideBtn").click();
        var result = $("#result").html();
        expect(result).toEqual('0.5');
    });
}); 
Private Module Testing

Hide   Shrink 

/// <reference path="Scripts/jquery-1.8.2.js" />
/// <reference path="Scripts/jasmine.js" />
/// <reference path="Scripts/publicmodule.js" />
/// <reference path="Scripts/privatemodule.js" />


describe("private tests:", function () {

    it("1 should be 3 on adding 1 and 2", function () {
        var result = privateModule.Add(1, 2);
        expect(result).toEqual(3);
    });
    
    it("2 should be 6 on adding 2 and 4", function () {
        var result = privateModule.Add(2, 4);
        expect(result).toEqual(6);
    });
    
    it("3 should be 3 on substract 6 and 3", function () {
        var result = privateModule.Substract(6, 3);
        expect(result).toEqual(3);
    });

    it("4 should be 2 on substract 6 and 4", function () {
        var result = privateModule.Substract(6, 4);
        expect(result).toEqual(2);
    });
    
    it("5 should be 18 on multiply 6 and 3", function () {
        var result = privateModule. Multiply(6, 3);
        expect(result).toEqual(18);
    });

    it("6 should be 24 on multiply 6 and 4", function () {
        var result = privateModule.Multiply(6, 4);
        expect(result).toEqual(24);
    });
    
    it("7 should be 2 on divide 6 and 3", function () {
        var result = privateModule.Divide(6, 3);
        expect(result).toEqual(2);
    });

    it("8 should be 1.5 on multiply 6 and 4", function () {
        var result = privateModule.Divide(6, 4);
        expect(result).toEqual(1.5);
    });

    it("9 should be 3 on calculate function with 1 and 2 for addBtn control", function () {
        var result = privateModule.Calculate("addBtn",1,2);
        expect(result).toEqual(3);
    });
    
    it("10 should be -1 on calculate function with 1 and 2 for substractBtn control", function () {
        var result = privateModule.Calculate("substractBtn", 1, 2);
        expect(result).toEqual(-1);
    });
    
    it("11 should be 2 on calculate function with 1 and 2 for multiplyBtn control", function () {
        var result = privateModule.Calculate("multiplyBtn", 1, 2);
        expect(result).toEqual(2);
    });
    
    it("12 should be 0.5 on calculate function with 1 and 2 for divideBtn control", function () {
        var result = privateModule.Calculate("divideBtn", 1, 2);
        expect(result).toEqual(0.5);
    });
  
}); 
Advertisement

Posted

in

by

Tags:

Comments

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: