面向JavaScript的測試架構:JsUnit的介紹和基本使用介紹,附有執行個體.
JavaScript單元測試架構JsUnit基本介紹和使用
XUnit framework
XUnit是一套标準化的獨立于語言的概念和結構集合,用于編寫和運作單元測試(Unit tests).
每一個語言都有一個用于單元測試的XUnit架構,比如Java有JUnit, C++有CppUnit, PHP有PHPUnit, Oracle SQL有UTPL/SQL.
JsUnit
JsUnit的官網: http://jsunit.net/
JsUnit遵循XUnit的一些慣例:
單元測試在JsUnit中叫做Test Functions.
Test Functions所在的HTML頁面叫做Test Page.
一個Test Page是一個包含jsUnitCore.js的HTML頁面. jsUnitCore.js提供了一些斷言函數, 比如assertEquals(comment, arg1, arg2).
JsUnit支援setUp()和tearDown().
Test Suite Page聲明了一個suite()函數,傳回一個JsUnitTestSuite, 用來運作含多個測試的套件.
JsUnit的testRunner.html頁運作Test Pages.
TestRunner頁面可以運作在一個檔案伺服器或者web伺服器上.
JUnit和JsUnit

JavaScript編碼規範
由于JavaScript沒有通路修飾符,是以通常在JavaScript中,不希望外界通路的成員和方法名以下劃線開始.
這是一種編碼規範,不是語言的規定,雖然外界仍然可以通路但是不推薦.
JsUnit測試函數要遵循的規則與JUnit3.8類似,比如說測試函數名以test開頭等.
JsUnit基本使用執行個體
待測試的源代碼:test1.js
function add(num1, num2)
{
return num1 + num2;
}
function subtract(num1, num2)
{
return num1 - num2;
}
function multiply(num1, num2)
{
return num1 * num2;
}
function addNumbers()
{
var v1 = document.getElementById("value1").value;
var v2 = document.getElementById("value2").value;
v1 = parseInt(v1);
v2 = parseInt(v2);
var v3 = v1 + v2;
document.getElementById("value3").value = v3;
}
測試頁面:test1.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> New Document </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<script type="text/javascript" src="..\jsunit2_2\jsunit\app\jsUnitCore.js"></script>
<script type="text/javascript" src="test1.js"></script>
<script type="text/javascript">
var count = 0;
// 此函數隻執行一次(在頁面加載後),類似于JUnit 4.x中的@BeforeClass
// 注意:并沒有與@AfterClass對應的函數存在
function setUpPage()
{
alert('setUpPage Invoked');
// 這行代碼必須放在setUpPage函數的最後一行
// 告訴JsUnit,setUpPage函數已經執行完畢
setUpPageStatus = "complete";
}
// setUp run before every test function
function setUp()
{
//alert(count++); //JUnit若這樣執行,count全是0,因為每一個測試方法都會生成新的測試對象;
//JsUnit會遞增count, 因為都是在同一個頁面裡去執行,是以會基于原有的值
//設定初始條件
document.getElementById("value1").value = 2;
document.getElementById("value2").value = 3;
}
// tearDown run after every test function
function tearDown()
{
//alert("tearDown");
//清理狀态
document.getElementById("value1").value = "";
document.getElementById("value2").value = "";
document.getElementById("value3").value = "";
}
// 以下為測試函數(Test Function)
function testAdd()
{
var result = add(1, 2);
assertEquals(3, result);
}
function testSubtract()
{
var result = subtract(1, 2);
assertEquals(-1, result);
}
function testMultiply()
{
var result = multiply(1, 2);
assertEquals(2,result);
}
function testAddNumbers()
{
addNumbers();
assertEquals("5", document.getElementById("value3").value);
}
</script>
</head>
<body>
<input type="text" id="value1"><br>
<input type="text" id="value2"><br>
<input type="text" id="value3"><br>
<input type="button" value="Add" onclick="addNumbers();">
</body>
</html>
使用JsUnit提供的測試運作器: testRunner.html, 加載測試頁面,即可運作相關測試,并報告結果.
setUp()和tearDown()
setUp()在每一個測試方法運作之前運作;
tearDown()在每一個測試方法運作之後運作.
對于JsUnit來說, 其setUp()和tearDown()方法與JUnit的運作原理是不同的.
JUnit中的setUp()和tearDown()之間是沒有關系的,也就是說不同的測試方法運作在不同的測試對象之中;
而JsUnit的各個測試函數是運作在同一個測試頁面中,是以同一個頁面中setUp()和tearDown()運作多次(每個測試函數之前和之後),會針對同一個變量進行操作.
setUpPage()
setUpPage()在測試頁面加載時執行,每次運作隻執行一次.
這個方法的末尾必須加上:
setUpPageStatus = "complete";
表示setUpPage()執行完成,否則會提示setUpPage not completed, 進而無法執行測試用例.
測試套件Suite
JsUnitTestSuite定義在jsUnitCore.js中, JsUnitTestSuite代表多個JsUnit測試頁面的套件,測試頁面和測試套件都可以被加在套件中,即套件是可嵌套的.(組合模式).
JsUnitTestSuite的定義(見jsUnitCore.js):
/**
* @class
* A JsUnitTestSuite represents a suite of JsUnit Test Pages. Test Pages and Test Suites can be added to a
* JsUnitTestSuite
* @constructor
*/
function JsUnitTestSuite() {
/**
* Declares that this object is a JsUnitTestSuite
*/
this.isJsUnitTestSuite = true;
/**
* @private
*/
this._testPages = Array();
/**
* @private
*/
this._pageIndex = 0;
for (var i = 0; i < arguments.length; i++) {
if (arguments[i]._testPages) {
this.addTestSuite(arguments[i]);
} else {
this.addTestPage(arguments[i]);
}
}
}
測試套件的使用例子1: test2.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> New Document </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<script type="text/javascript" src="..\jsunit2_2\jsunit\app\jsUnitCore.js"></script>
<script type="text/javascript">
//測試套件名一定為suite
function suite()
{
var testSuite = new top.jsUnitTestSuite();
// 增加的測試頁面的路徑是相對于測試運作器(testRunner.html)的路徑
// 而不是目前頁面
testSuite.addTestPage("../../jsUnit_code/test1.html");
testSuite.addTestPage("../../jsUnit_code/test1.html");
testSuite.addTestPage("../../jsUnit_code/test1.html");
return testSuite; // 最後需要傳回套件
}
</script>
</head>
<body>
</body>
</html>
測試套件的使用例子2: test3.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title> New Document </title>
<meta name="Generator" content="EditPlus">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<script type="text/javascript" src="..\jsunit2_2\jsunit\app\jsUnitCore.js"></script>
<script type="text/javascript">
// 自定義的測試套件
function mySuite()
{
var testSuite = new top.jsUnitTestSuite();
testSuite.addTestPage("../../jsUnit_code/test1.html");
testSuite.addTestPage("../../jsUnit_code/test1.html");
testSuite.addTestPage("../../jsUnit_code/test1.html");
return testSuite;
}
function suite()
{
var testSuite = new top.jsUnitTestSuite();
testSuite.addTestPage("../../jsUnit_code/test1.html"); // 在測試套件中加入頁面
testSuite.addTestSuite(mySuite()); // 在測試套件中加入測試套件
return testSuite; // 記得傳回套件
}
</script>
</head>
<body>
</body>
</html>
參考資料
聖思園張龍老師Java Web教育訓練視訊教程: 60-62.
JsUnit官網: http://jsunit.net/
作者: 聖騎士Wind
出處: 部落格園: 聖騎士Wind
Github: https://github.com/mengdd
微信公衆号: 聖騎士Wind