prettify

baseline

Javascript Unit Testing TDD

A simple HTML Page that runs all your unit tests (Only Is.Equal is implemented but more are coming).
The web app should be build as MVC or at least have a distinct Model (set of .js files).
Create a Folder "UnitTest".
Put the following files inside.

External dependencies

  • ins/ins.js
  • ins/Stopwatch.js
Scripts.Add all the scripts that contain the Model to be tested.
Add all the tests.

Tests.js

"use strict";
Scripts.Add("../Samples/Sample.js");
Tests["BaumeInd convert @20"] = [
    function () {
        var oSample = new Sample();
        oSample.nSamBaumeInd = 12;
        oSample.nSamBaumeTemp = 20;
        Expect(oSample.BaumeInd20(), Is.EqualTo(12), "12@20 ⇒ 12");
        oSample.nSamBaumeTemp = 18;	
        Expect(oSample.BaumeInd20(), Is.EqualTo(11.9), "12@18 ⇒ 11.9");
        oSample.nSamBaumeTemp = 22;
        Expect(oSample.BaumeInd20(), Is.EqualTo(12.1), "12@22 ⇒ 12.11");
    }
];
Tests["Baume ⇒ Sugar"] = [
    function () {
        var oSample = new Sample();
        oSample.nSamBaume = 16.8;
        Expect(oSample.Baume2Sugar(), Is.EqualTo(320.8), "Baume: 6.8 ⇒ Sugar");
    }
];
Include, but DO NOT MAKE ANY CHANGES:

UnitTest.htm

<!DOCTYPE html>
<html>
<head>
    <title>Unit Tests</title>
<link rel="stylesheet" href="UnitTest.css" />
</head>
<body>
<button id="btnRun">Run</button>
<table id="tabResults"><thead><tr>
<th></th><th>Actual</th><th>Expected</th><th>Description</th>
</tr></thead><tbody></tbody></table>

<script src="../ins/ins.js"></script>
<script src="../ins/StopWatch.js"></script>
<script src="UnitTest.js"></script>
<script src="Tests.js"></script>
</body>
</html>

UnitTest.css

#tabResults {
    border-collapse:collapse;
}
#tabResults td,
#tabResults th {
    border:1px solid #999;
}
#tabResults th {
    text-align:left;
    font-weight:normal;
}
#tabResults td:first-child {
    text-shadow:
        -1px -1px 0 #999,
        1px -1px 0 #999,
        -1px 1px 0 #999,
        1px 1px 0 #999;
    font-size:1.2em;
    font-weight:bold;
}
#tabResults .Titlos {
    background-color:#def;
    text-shadow:none !important;
}
#tabResults td fieldset {
    padding:2px;
    margin:0;
    font-weight:normal !important;
    background-color:#fdd;
}
#tabResults td fieldset legend {
    background-color:#fed;
    border-width:1px 1px 0 1px;
    border-style:solid;
}

UnitTest.js

"use strict";
var Scripts = {};
var Tests = {};
//============================================================================================
var oC = {}
oC.oSW = new ins.Stopwatch();
oC.Startup=function() {
    var oScr, nPos;
    for (nPos = 0; nPos < Scripts.length; nPos++) {
        oScr = document.createElement("script");
        oScr.src = Scripts[nPos];
        document.getElementsByTagName("body")[0].appendChild(oScr);
    }
    $("btnRun").onclick = oC.Run;
}
oC.Run = function () {
    var oTbody = $("tabResults").querySelector("tbody");
    var nPos;
    oTbody.Clear();
    var oTest, oTd;
    for (var sKey in Tests) {
        if (!Tests.hasOwnProperty(sKey)) continue;
        oTd = oV.Test(sKey);
        oTest = Tests[sKey];
        this.oSW.Start();
        try {
            for (nPos = 0; nPos < oTest.length; nPos++) {
                oTest[nPos]();
            }
        } catch (ex) {
            oV.TestError(oTd, ex);
        } finally {
            this.oSW.Stop();
        }
        oV.TestTitle(oTd, sKey + " (" + this.oSW.toString() + ")");

    }
};
oC.nScripts = 0;
oC.ScriptLoaded = function () {
    oC.nScripts--;
    if (oC.nScripts <= 0) oC.Run();
};
Scripts.Add = function (sScript) {
    oC.nScripts++;
    var oScr = document.createElement("script");
    oScr.onload = oC.ScriptLoaded; //ie9
    oScr.src = sScript;

    document.body.appendChild(oScr);
};
document.addEventListener("DOMContentLoaded", oC.Startup, false);
//============================================================================================
var oV = {}
oV.Expect = function (oResult) {
    var oTbody = $("tabResults").querySelector("tbody");
    var oTr,oTd;
    oTr=oTbody.a$("tr").
        a$("td", { t: (oResult.bResult ? "✔" : "✘"), "style": "fontWeight:bold;color:#" + (oResult.bResult ? "0f0" : "f00") }).parentNode.
        a$("td", { t: oResult.Expected.toString(),"style":"textAlign:"+(typeof oResult.Expected === "number"?"right":"left") }).parentNode.
        a$("td", { t: oResult.Actual.toString(), "style": "textAlign:" + (typeof oResult.Actual === "number" ? "right" : "left") }).parentNode.
        a$("td", { t: oResult.sMsg });
};
oV.Test = function () {
    var oTbody = $("tabResults").querySelector("tbody");
    return oTbody.a$("tr").a$("td", {"class":"Titlos", colSpan:4});
};
oV.TestTitle = function (oTd, sTitle) {
    oTd.a$({ t: sTitle });
};
oV.TestError = function (oTd, oEr) {
    oTd.a$("fieldset", {"class":"Error"}).a$("legend", { t: "Error" }).parentNode.
    a$({ style: "", t: 
    "Name: " + oEr.name+
    "\nMessage: " + oEr.message +
    (oEr.number? "\nNumber: " + (oEr.number & 0xFFFF).toString():"")+
    (oEr.fileName ? "\nfileName: " + oEr.fileName : "")+
    (oEr.lineNumber ? "\nlineNumber: " + oEr.lineNumber : "")+
    (oEr.stack ? "\nstack: " + oEr.stack : "")+
    (oEr.toSource ? "\nSource: " + oEr.toSource() : "")
    });
};
//============================================================================================
var Expect = function (Val, Obj, sMsg) {
    if (Obj.operator === "===") {
        oV.Expect({
            bResult: (Val === Obj.value),
            Expected: Val,
            Actual: Obj.value,
            sMsg: sMsg
        });
    }
};
var Is = {};
Is.EqualTo = function (obj) {
    var oRet = {};
    if (typeof obj === "number") {
        oRet.type = "number";
        oRet.value = obj;
        oRet.operator = "===";
    }
    return oRet;
};

No comments:

Post a Comment