Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

Testing Public and Private Functions in JavaScript using Jasmine and Chutzpah

5.00/5 (3 votes)
31 Mar 2014CPOL1 min read 14.3K   60  
JavaScript Testing

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.

HTML
@{
    ViewBag.Title = "Home Page";
}
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/publicmodule.js"></script>
<script src="~/Scripts/privatemodule.js"></script>
<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>

<script type="text/javascript">
    publicModule.Init();
</script> 

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
JavaScript
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
JavaScript
/*
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
JavaScript
/// <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
JavaScript
/// <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);
    });
  
}); 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)