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.
@{
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:
-
Public
module, which will interact with HTML for
all the display logic sides -
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 ($) {
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));
$("#result").html(result);
});
};
var api = {
Init: init,
};
return api;
}(jQuery));
Private Module
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
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
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);
});
});