董宁 王波
摘要 运行和调试JavaScript代码的主要工具是Web浏览器,现代Web浏览器一般包含调试JavaScript代码的控制台。JavaScript代码运行中的错误信息、Ajax调用、性能分析结果、命令行执行结果都会显示在控制台界面上。Firefox浏览器的Firebug提供了很多手段,可以将JavaScript代码运行中的信息输出到Firebug控制台。通过灵活使用控制台语句,可以方便地实现对JavaScript代码的单元测试。
关键词 JavaScript ;控制台;单元测试
DOI DOI: 10.11907/rjdk.162418
中图分类号: TP306
文献标识码: A 文章编号 文章编号: 16727800(2017)002001303
0 引言
在计算机编程中,单元测试[1]是针对程序模块(软件设计的最小单位)进行正确性检验的测试工作。程序单元是最小的测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类或者派生类(子类)中的方法。每个理想的测试案例独立于其它案例。为测试时隔离模块,经常使用stubs、mock或fake等测试马甲程序。单元测试通常由软件开发人员编写,用于确保所写代码符合软件需求和遵循开发目标。
运行和调试JavaScript代码[2]的主要工具是Web浏览器,现代的Web浏览器一般包含调试JavaScript代码的控制台。对于JavaScript代码,Mozilla Firefox是最适合运行与调试的浏览器之一。Mozilla Firefox浏览器的插件Firebug是调试JavaScript代码必不可少的,尤其是涉及到Ajax技术的Web应用。在Mozilla Firefox浏览器中安装好Firebug插件后,JavaScript代码运行中的错误信息、Ajax调用、性能分析结果、命令行执行结果都会显示在控制台界面上。Firebug提供了很多手段可以将JavaScript代码运行中的信息输出到Firebug控制台,通过灵活使用控制台语句可以方便实现对JavaScript代码的单元测试。
1 JavaScript代码中控制台语句使用
在JavaScript代码中可以使用console.log()方法向控制台输出信息。实际上,console.log()方法包含在conosle对象中,而console对象则是由浏览器提供的(IE6及以前浏览器不支持console对象)。
除了最基本的console.log()方法外,conosle对象还提供了多种方法以便向控制台输出不同类型的信息和调试JavaScript代码。
(1)不同类型输出方法。
根据信息的不同性质,console对象除了console.log()方法外还有4种输出信息方法:一般信息console.info()、调试信息console.debug()、警告提示console.warn()和错误提示console.error()。
(2)自定义输出格式。
console对象所有的输出方法都可以使用printf风格的占位符对输出内容进行格式化。支持的占位符有字符(%s)、整数(%d或%i)、浮点数(%f)和对象(%o)。
(3)分组输出。
如果在JavaScript代码运行过程中需要输出数据太多,则可以使用分组的方式输出到控制台以便查看和分析。conosle对象中的console.group()和console.groupEnd()方法提供了数据分组输出功能。
(4)输出指定对象所有属性和方法。
console.dir()方法可以输出传入对象的所有属性和方法。
(5)显示页面对象的HTML代码。
console.dirxml()方法可以显示输入的页面对象HTML代码,以便查看和调试。
(6)断言。
console.assert()方法提供了基本的代码测试功能。该方法用来判断一个表达式或变量是否为真,如果不为真,则在控制台输出一条相应信息,并且抛出一个异常。
(7)跟踪方法调用轨迹。
console.trace()方法可以用来追踪方法的调用轨迹,用来对递归方法或调用过程较复杂的方法进行分析。
(8)计时方法。
console.time()和console.timeEnd()方法可以用来记录并输出代码的运行时间。
(9)性能分析方法。
性能分析指分析程序各个部分的运行时间,console.profile()可以用来对JavaScript代码进行性能分析,找出代码瓶颈。
2 JavaScript代码单元测试实现
如果需要测试某些不涉及DOM和CSS操作的JavaScript代码,用Qunit之类的第三方JavaScript单元测试框架[3]略显繁琐,效率不高,这类JavaScript代码最适合用控制台语句做单元测试。
例如某项目需要用JavaScript代碼实现快速排序[4],具体实现代码如下:
//swap函数实现元素交换
function swap(list,firstIndex,secondIndex){
var temp = list[firstIndex];
list[firstIndex]= list[secondIndex];
list[secondIndex]=temp;
}
//getMiddle函数获取中轴点
function getMiddle(list,left,right) {
var pivot = list[Math.floor((right + left)/2)];
var i = left;
var j = right;
while (i <= j) {
while (list[i]< pivot) {
i++;
}
while (list[j]> pivot) {
j--;
}
if (i <= j) {
swap(list,i,j);
i++;
j--;
}
}
return i;
}
//quickSort函数以递归方式完成快速排序
function quickSort(list,left,right) {
var index;
if (list.length > 1) {
index = getMiddle(list,left,right);
if (left < index - 1) {
quickSort(list,left,index - 1);
}
if (index < right) {
quickSort(list,index,right);
}
}
return list;
}
上述快速排序的实现代码可以使用控制台语句中的断言部分完成测试,具体如下:
//待排序list
var array=[6,2,9,8,1,7];
//预期的结果
var result=[1,2,6,7,8,9];
//测试swap函数
swap(array,1,5);
console.assert(array[1]==7&&array[5]==2,"swap函数错误!");
//测试getMiddle函数
var m = getMiddle(array,0,array.length-1);
console.assert(m==5,"getMiddle函数错误!");
//测试quickSort函数
quickSort(array,0,array.length-1);
console.assert(array.toString()==result.toString(),"quickSort函数错误!");
//单元测试结束
console.info("测试完成!");
通过控制台语句中的console.assert()方法可以分别测试代码中的swap函数、getMiddle函数和quickSort函数。如果测试通过,则会看到在控制台中输出带有信息提示图标的“测试完成!”字样。
如果其中某一个函数出错则会有相应提示,如图1所示。
上述针对快速排序模块的测试很简单,测试结果也没有问题。但是对单元测试来说,这个测试用例太单一和普通了。为了提高测试用例[5]覆盖率,最好写一个辅助函数tester来调用被测试代码和使用控制台语句输出结果,具体做法如下:
function tester(name,result,expect){
//使用分组语句输出测试用例名
console.group(name);
if(result==expect){
//测试通过,信息提示
console.info("通过!");
}else{
//测试失败,警告提示
console.warn("失败");
}
//分组结束
console.groupEnd();
}
如果用上述tester函数测试完成快速排序的quickSort函数,可以这样实现:
//待排序list
var array1=[6,2,9,8,1,7];
//预期的结果
var result1=[1,2,6,7,8,9];
//待排序list2
var array2= [6,2,9,8,1,7,85,12,48,56,78,987,45,
12,-78,45,0,58,96,12.56,12.3,7.36];
//预期的结果2
var result2 = [-78,0,1,2,6,7,7.36,8,9,12,12,12.3,
12.56,45,45,48,56,58,78,85,96,987];
//错误结果测试
tester("测试错误输入",1,0);
//测试快速排序
quickSort(array1,0,array1.length-1);
tester("常规测试",array1.toString(),result1.toString());
quickSort(array2,0,array2.length-1);
tester("包含负数与小数测试",array2.toString(),result2.toString());
代码运行结果如图2所示。
可使用tester函数添加许多测试用例,并且还能为用例命名,在控制台中直接显示每个用例是否通过,同时用不同颜色标记,使结果一目了然。至此一个基本的单元测试就完成了。
3 结语
快速排序算法的JavaScript代码,灵活使用控制台语句可快速完成代码模块的单元测试,比起专业的第三方JavaScript单元测试框架更高效,学习曲线也不那么陡峭。但是,利用控制台语句实现JavaScript代码单元测试主要适用于逻辑代码,而前端开发很多时候要和UI关联,虽然UI相关的代码也可以进行单元测试,但很麻烦,比起逻辑代码难度大得多。随着单元测试的普及,尤其是敏捷开发的推动,涌现了许多优秀的JavaScript单元测试框架,如Qunit和Jasmine等,每个都有各自擅长的领域。对于基于JavaScript语言的前端项目单元测试,结合控制台语句,精心选择框架,综合考虑项目实际情况,一定可以写出合适的测试代码。
参考文献:
[1] 张军,李攀,邢光辉,等.软件测试的认知误区和单元测试实战流程[J].科技创新与应用,2016 (25):120120.
[2] 張令芬.JavaScript API自动化测试方案的管理设计与实现[J].电子设计工程,2016,24(2):3537,41.
[3] 王婷婷,申启杰.JavaScript调试器软件架构[J].湖南师范大学学报,2014(6):8892.
[4] 王善坤,陶祯蓉.一种三路划分快速排序的改进算法[J].计算机应用研究,2012,29(7):25132516.
[5] 张智轶,陈振宇,徐宝文,等.测试用例演化研究进展[J].软件学报,2013,24(4):663674.
(责任编辑:杜能钢)