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/