第
5
章
软件测试工具
本章将对多种测试工具进行详细介绍,并通过具体实例对BoundsChecker、
JUnit、LoadRunner、Monkey等测试工具,以及测试管理工具禅道进行演示。
..5.1白盒测试工具BoundsChecker
BoundsChecker是一种常用的动态白盒测试工具,其常用于单元测试中的
代码错误检查,使用简单且高效。下面将对其进行详细介绍,帮助读者更快地
了解以及学会使用该工具。

5.1 
安装
1.
BoundsChecker是集成在VisualC+
+ 
上的一个插件,因此在安装
BoundsChecker之前,首先要确保计算机中已经安装了VisualC++。在获得
BoundsChecker安装程序后,以管理员的身份运行setup.exe文件,按照提示进
行安装即可。安装成功以后,可在VisualC++环境下看到名为BoundsChecker 
的菜单,如图5.

1所示。


图5.r在V+环境下的菜单

1 
BoundsCheckeisualC+


134软件测试技术与研究
5.1.2功能与模式
BoundsChecker是一个功能强大、使用方便的代码检查工具,在程序运行期间,它可
以跟踪以下3种程序错误。
(1)指针操作和内存、资源泄露错误。例如,对指针变量的错误操作、内存泄漏等
问题。
(2)内存的错误操作。例如,未初始化内存空间即使用,内存的读写溢出等错误。
(3)API函数使用错误。
BoundsChecker提供两种模式给用户进行错误检测:一种为ActiveCheck;另一种为
FinalCheck。与FinalCheck模式相比,ActiveCheck检测的错误类型有限,一般为内存泄
漏错误、资源泄露错误、API函数使用错误。而FinalCheck则包含了BoundsChecker可
以检测的所有的错误类型,除ActiveCheck可以检测的错误类型之外,还可以对指针错误
操作、内存溢出等内存操作错误进行检测,提供更详细的错误信息,其是ActiveCheck的
超集。
5.1.3ActiveCheck模式
使用ActiveCheck模式检查的步骤如下。
(1)在VisualC++环境下打开要测试的程序,并使程序处于Debug状态下。
(2)选择BoundsChecker菜单中的IntegratedDebugging与ReportErorsand 
Events命令,确保BoundsChecke如图5.
r可以发挥作用,2所示。

(3)选择VisualC+
+ 
Build菜单的StartDebug→Go命令,使程序在Debug状态下
运行,ActiveCheck也将在后台下启动并进行错误检测。当程序运行结束后, 
BoundsChecker将给出错误报告。
y命令,3所示,
(4)如果选择ReportErorsImmediatel如图5.则当检测到错误发生
时会立即停止运行,并弹出错误提示框,4所示。
如图5.


图5.r菜单选项(一) 图5.r菜单选项(二)

2 
BoundsChecke3 
BoundsChecke

单击第1个按钮表示暂时忽略这个错误,继续运行程序。
单击第2个按钮BoundsChecker会跳转到程序出现问题的代码处。待处理完问题, 

可选择Debug→go命令继续运行。
单击第3个按钮表示将该错误添加至可忽略列表,对以后出现的此错误不予报告。
单击第4个按钮表示终止程序的运行。
单击第5个按钮会显示当前的内存使用情况。


第5章软件测试工具135
图5.4错误提示框
单击第6个按钮会显示当前错误的有关帮助信息。
单击第7个按钮即代表选择ReportErrorsImmediately命令。
单击第8个按钮代表选择ReportErrorsandEvents命令。
单击第9个按钮会显示或者隐藏与错误相关的函数调用堆栈情况。
5.1.4FinalCheck模式
如需在FinalCheck模式下测试程序,则不能使用VisualC++集成开发环境提供的
编译连接器来构造程序,而必须要使用BoundsChecker提供的编译连接器。当
BoundsChecker的编译连接器编译连接程序时,会向程序中插桩一些错误检测代码,因此
FinalCheck能够比ActiveCheck找到更多的错误。

使用FinalCheck模式进行错误检查的步骤如下。

(1)在VisualC++环境下打开要测试的程序。
(2)选择Build菜单的Configurations命令。
(3)在弹出的对话框中单击Add按钮,在Configuration文本框中添加需要创建的文
件夹名称。
(4)在Copysetingsfrom组合框中选择×××-Win32Debug选项,单击OK按钮, 
然后再单击Close按钮即可。
(5)选择Build菜单的SetActiveConfiguration命令,选中步骤(3)中新建的文件夹, 
单击OK按钮,这样BoundsChecker的编译连接器编译连接程序时生成的中间文件、可
执行程序都会被放到该文件夹下。
(6)选择BoundsChecker菜单的RebuildAlwithBoundsChecker命令,对程序重新
进行编译连接。在这个过程中,BoundsChecker将会向被测程序的代码中加入错误检
测码。
(7)选择BoundsChecker菜单中的IntegratedDebugging与ReportErorsand 
Events命令。
(8)运行VisualC++环境中Build菜单的StartDebug→Go命令,程序将在Debug
状态下运行。
两种模式都可以对程序进行检测,但正如5.2节所述,Acieek所能检测的错

1.tvChc


136软件测试技术与研究
误类型有限,而FinalCheck模式下可以检测BoundsChecker所能支持检测的所有错误类
型,与此同时,FinalCheck需要付出运行速度变慢的代价。
5.1.5结果分析
在程序结束以后,BoundsChecker会给出一份错误列表,其将包含程序中出现的内存
泄漏、指针操作错误、API 函数使用错误以及资源泄漏等错误,如图5.5所示。测试人员
需要根据错误列表进行分析,找到错误原因以及位置。
从图5.5中可以看出,左边的窗格中逐条给出了程序在内存、资源、API 函数使用上
的问题,包括问题的类型、出现次数、具体问题描述等。在单击某条问题时,右边窗格会显
示与该问题相关的函数调用堆栈情况,双击某条问题时,BoundsChecker会定位到引起该
问题的源代码处。
图5.错误列表

5 

虽然BoundsChecker给出了较为详尽的错误报告,但测试人员仍然需要发挥主观能
动性进行分析。因为工具的使用只能帮助测试人员更快捷方便地检测,但无法保证其结
果是完全正确的。在使用中BoundsChecker会存在误报的情况,其可能有以下两种情
况:第一种是由于工具算法问题将正常的代码检测为错误;第二种是由于
BoundsChecker指出的问题存在于第三方代码中,如第三方的程序库等。对于错误列表
中的错误,测试人员应该进行仔细分析,在确认非程序出错时可将错误设为忽略,以防下
次再提醒。

..5.单元测试工具JUnt

2i
5.2.1 
JUnit简介
JUnit是一个可编写重复测试的简单框架,是基于XUnit架构的单元测试框架实例。
它由KentBeck和ErichGamma 建立,并逐渐成为源于KentBeck,SUnit的XUnit家族
中最为成功的一个。

JUnit测试主要用于程序员测试,即白盒测试,因为程序员知道被测试的软件如何完
成功能和完成什么样的功能。JUnit是一套框架,其继承TestCase类,现在大多数Java 
开发环境都已经集成了JUnit作为自带单元测试的工具。


第5章 软件测试工具1 37 
5.2.2 JUnit的优势与核心功能
1.JUnit的优势 
(1)简化测试代码的编写,每个单元测试用例相对独立并由JUnit启动,自动调用, 
不需要添加额外的调用语句。
(2)可以书写一系列的测试方法,对项目所有的接口或者方法进行单元测试。
(3)添加、删除、屏蔽某条测试方法时不影响其他的测试方法,几乎所有开源框架都
对JUnit有相应的支持。
(4)能使测试单元保持持久性。
2.JUnit的核心功能
(1)测试用例(TestCase):创建和执行测试用例。
(2)断言(Assert):自动校检测试结果。
(3)测试结果(TestResult):测试的执行结果。
(4)测试运行器(Runner):组织和执行测试。
5.2.3 根据血糖判断健康状况
本案例主要根据空腹血糖以及餐后两小时血糖联合进行健康判断,判断标准如表2.1。
1.创建测试类
首先创建被测类,部分核心代码如下: 
public class BloodSugar { 
private double empty; 
private double later; 
public double getEmpty() { 
return empty; 
} 
public void setEmpty(double empty) { 
this.empty = empty; 
} 
public double getLater() { 
return later; 
} 
public void setLater(double later) { 
this.later = later;

1 38 软件测试技术与研究 
} 
public void setParams(double e,double l){ 
this.empty=e; 
this.later=l; 
} 
public BloodSugar(double e,double l){ 
this.empty=e; 
this.later=l; 
} 
}p
ublic String GetBloodSugarType() { 
String result = ""; 
if (empty >7. 0 & later >11. 1) { 
result = "糖尿病"; 
} else if (empty <6. 1 & later <7. 8) { 
result = "正常血糖"; 
}else if (empty < 7. 0 & later <=11. 1 & later >=7. 8) { 
result = "糖耐量减低"; 
} else if (empty >=6. 1 & empty <= 7. 0 & later <7. 8) { 
result = "空腹血糖受损"; 
} else { 
result ="血糖值错误"; 
} 
return result; 
} 
编写完成后可以写几个简单的测试用例测试一下。 
public static void main(String[] args){ 
BloodSugar test=new BloodSugar(7.5,12); 
System.out.println(test.GetBloodSugarType()); 
test.setParams(5,6); 
System.out.println(test.GetBloodSugarType()); 
test.setParams(6,8); 
System.out.println(test.GetBloodSugarType()); 
test.setParams(6.5,7.5); 
System.out.println(test.GetBloodSugarType()); 
test.setParams(1,200); 
System.out.println(test.GetBloodSugarType()); 
}

第5章软件测试工具139
单击运行后结果如图5.6所示。
图5.6测试结果
可以看到,程序的功能已经基本实现,可以根据输入的空腹血糖值和餐后两小时血糖
值判断人的健康情况。
在被测类代码处右击,在弹出的快捷菜单中选择GoTo→Test命令,如图5.7所示, 
创建测试脚本。
图5.创建测试脚本

7 

继续选择CreateNewTest命令, 如图5.

新建脚本,8所示。


图5.新建脚本

8 


1 40 软件测试技术与研究
选用JUnit4测试库进行测试,如图5.9所示,创建JUnit测试类。
图5.9 创建JUnit测试类
选中需要测试的类和方法后,即可自动生成JUnit测试类,部分代码如下所示: 
@Test 
public void getBloodSugarType() { 
} @Test 
public void main() { 
} 
2.编写测试方法
使用JUnit生成测试脚本,并编写部分代码如下: 
public class BloodSugarTest { 
BloodSugar testObj; 
@Before 
public void setUp() throws Exception { 
testObj=new BloodSugar(); 
System.out.println("Run @Before method"); 
}

第5章 软件测试工具1 41 
@After 
public void tearDown() throws Exception { 
testObj = null; 
System.out.println("Run @After method"); 
} 
@BeforeClass 
public static void prepareEnvironment(){ 
System.out.println("Run @BeforeClass method"); 
} 
@AfterClass 
public static void RestoreEnvironment(){ 
System.out.println("Run @AfterClass method"); 
} 
}
测试用例的执行顺序如下。
(1)@Before:在每个测试用例执行之前执行一次。
(2)@After:在每个测试用例执行之后执行一次。
(3)@BeforeClass:在测试类的所有测试用例执行之前执行一次。
(4)@AfterClass:在测试类的所有测试用例执行之后执行一次。
继续编写测试用例,部分代码如下: 
@Test 
public void getBloodSugarType() { 
System.out.println("Run getBloodSugarType"); 
testObj.setParams(6,7); 
String actual=testObj.GetBloodSugarType(); 
String expect="正常血糖"; 
assertTrue(expect==actual); 
}
其中,GetBloodSugarType的作用即调用被测方法。
assertTrue即断言,其可以判断预期结果expect和运行结果actual的差别。 
@Category({EPTest.class}) 
@Test 
public void getBloodSugarType_1(){ 
System.out.println("Run getBloodSugarType1"); 
testObj.setParams(6,8); 
assertTrue(testObj.GetBloodSugarType()=="糖耐量减低");

1 42 软件测试技术与研究 
} @Category({EPTest.class}) 
@Test 
public void getBloodSugarType_2(){ 
System.out.println("Run getBloodSugarType2"); 
testObj.setParams(6.5,7); 
assertTrue(testObj.GetBloodSugarType()=="空腹血糖受损"); 
} @Category({EPTest.class}) 
@Test 
public void getBloodSugarType_3(){ 
System.out.println("Run getBloodSugarType3"); 
testObj.setParams(7,11.1); 
assertTrue(testObj.GetBloodSugarType()=="糖尿病"); 
}
这里用了@Category 注解,JUnit提供了一种分类运行器,其包含在org.junit. 
experimental.categories.Category中,基本步骤分成两步。
(1)创建新的测试类,并配置该测试类。
(2)修改已有测试类,定义具有特定分类的方法。
采用这种分类器可以将测试用例分类,以满足不同的测试类型。
在应用到测试用例之前首先完成第一步,创建新的测试类,其代码如下。 
@RunWith(Categories.class) 
@Categories.IncludeCategory({EPTest.class}) 
@Suite.SuiteClasses({BloodSugarTest.class}) 
public class CategoryTest { 
}
@RunWith注解指定运行器;IncludeCategory设置要执行的测试特性为EPTest,测
试特性也可被理解为专有一类测试的标签;SuiteClasses 设置候选测试集为
BloodSugarTest。
第二步修改已有测试类,在@Category注解后加上{EPTest.class}以表明该测试用
例的标签。
注意在使用EPTest标签之前必须要先定义EPTest接口类,其代码如下。 
public interface EPTest { 
}
之后该代码即可执行,执行结果如图5.10所示。