Click here to Skip to main content
15,868,016 members
Articles / Web Development / HTML
Tip/Trick

Testing Public and Private Functions in JavaScript using Jasmine and Chutzpah

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
31 Mar 2014CPOL1 min read 13.9K   60   6  
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)


Written By
Software Developer (Senior)
Australia Australia
I am a, hands-on, Microsoft C# Analyst Programmer using Xamarin, Azure, WPF and MVC as my preferred tools, also as Team Lead and Scrum Master. My experience include in analysis, object oriented design, development and implementation of client, server, web and windows based applications and enterprise mobile apps using latest Microsoft technologies such as MVC, WPF and Xamarin Forms.

I have worked with Microsoft technologies for over 10 years building software for various private sector companies, applying both technical knowledge and managerial expertise.

My preferred technology stack includes C#, Azure, WPF, MVC, Entity Framework, Xamarin and SQL Server and highly prefer working on various design patterns and architectures.

An integral part of my work is to provide my clients with a high standard of understandable technical documentation: I have written few articles listed few page down in this resume, designs, as well as User Guides.

Using Azure for over 1.5 year, migrating application to the cloud, fully managed continuous integration for all environments.

Comments and Discussions

 
-- There are no messages in this forum --