1.1 概述
一段时间以来,软件开发业一直在推崇单元测试、编程标准执行、指标评估和按合同设计(Designby Contract)等技术。如果能实施这些技术,就能极大地改善软件的可靠性并减少开发时间和成本。但是直到目前为止,由于需要复杂而庞大的工作量,只有很少的开发人员能够实际采用它们。Jtest实现了自动化的解决方案,排除了Java开发人员技术应用上的障碍,使得开发人员能够顺利地采用这些技术。成功地开发可靠的Java软件有两个关键方面:通过贯彻执行Java编程标准减少出错概率;通过彻底测试每个新写的类将错误扼杀在萌芽状态。
Jtest是第一个自动化Java单元测试工具。Jtest自动测试任何Java类或部件,而不需要您写一个测试用例、驱动程序或桩函数。只要点击一个按钮,Jtest自动测试代码构造(白盒测试)、测试代码功能性(黑盒测试)、维护代码完整性(回归测试)和静态分析(编程标准执行和指标度量)。不需要复杂的设置,Jtest能够立即使用并指出问题。如果您使用“按合同设计”技术在代码中加入描述信息,Jtest能够自动建立和执行测试用例验证一个类的功能是否符合其功能描述。
Jtest能够帮助您防止错误,其可定制的静态分析特性让您能够自动执行超过240个软件业认可的编程标准,建立和执行任何数量的定制编程标准,并对它们进行剪裁以适应特定的项目和团队。
优势:
1)使预防代码错误成为可能,从而大大节约成本,提高软件质量和开发效率
2)使单元测试,包括白盒、黑盒以及回归测试成为可能
3)使代码规范检查和自动纠正成为可能
4)鼓励开发团队横向协作来预防代码错误
特征:
1)通过简单的点击,自动实现代码基本错误的预防,这包括单元测试和代码规范的检查
2)生成并执行junit单元测试用例,对代码进行即时检查
3)提供了进行黑盒测试、模型测试和系统测试的快速途径
4)确认并阻止代码中不可捕获的异常、函数错误、内存泄漏、性能问题、安全弱点的问题
5)监视测试的覆盖范围
6)自动执行回归测试
7)支持DbC编码规范
8)检验超过350个来自java专家的开发规范
9)自动纠正违反超过160个编码规范的错误
10)允许用户通过图形方式或自动创建方式来自定义编码规范
11)支持大型团队开发中测试设置和测试文件的共享
12)实现和EclipseIDE 的安全集成
1.2 工作原理
Jtest通过自动实现java的单元测试和代码标准校验,来提高代码的可靠性。Jtest先分析每个java类,然后自动生成测试用例并执行用例,从而实现代码的最大覆盖,并将代码运行时未处理的异常暴露出来;另外,它还可以检查以DbC(Designby Contract)规范开发的代码的正确性。用户还可以通过扩展测试用例的自动生成器来添加更多的用例。Jtest还能按照现有的超过350个编码标准来检查并自动纠正大多数常见的编码规则上的偏差,用户可自定义这些标准,通过简单的几个点击,就能预防类似于未处理异常、函数错误、内存泄漏、性能问题、安全隐患这样的代码问题。
1.3 基本概念
开发人员常常把单元测试当作模块测试。通常模块是指一个大应用的一部分,如一个应用模块或一个子程序。在这里我们有所区别,我们指的单元测试是针对一个应用中的基本单元或部件;在Java中,是测试一个类。
Jtest的测试生成系统专利技术(patent#5,784,553 & #5,761,408)为开发人员提供了一种省时有效的白盒测试方法。Jtest通过自动生成和执行能够全面测试类代码的测试用例,使白盒测试完全自动化。Jtest使用一个符号化的虚拟机执行类,并搜寻未捕获的运行时异常。对于检测到的每个未捕获的运行时异常,Jtest报告一个错误,并提供导致错误的栈轨迹和调用序列。Jtest的先进技术保证它能够自动测试类的所有代码分支,从而彻底检查被测类的结构。
换句话说,Jtest自动生成高质量的测试用例集合,发现尽可能多的结构性错误,而且:
· 不需要用户写一点测试脚本语言或测试用例。
· 不需要用户写测试驱动程序。
· 不修改源代码。
· 不要求完整的应用。
Jtest报告下列未捕获的运行时异常:
· 行为错误的方法:这些方法对于某些特定输入不会产生异常。必须修改这些代码。
· 非预期参数:这一问题出现在当某方法遇到非预期的输入(不知任何处理)而产生一个异常。这些问题的修正可以通过检查输入并产生一个IllegalArgumentException (IAE)(假如该输入是非法的)。改正这类问题可以使代码更清晰更易维护。
· 行为正确的方法:这时,方法的正确输出是产生一个异常。在这种情形下,建议开发人员修改代码,将这类异常的产生置于方法的throw子句中。这会得到更清晰的代码并易于维护。
· 仅为开发人员使用的方法:在这种情况下,这些方法"不被假设"成处理Jtest生成的输入,开发人员是这些方法的唯一使用者,并且不传递这些输入参数。最好的办法是修改这些代码,让它产生一个IAE。这将带来额外的好处,使代码更易阅读。
总之,通过执行自动白盒测试,并提示上述类型的问题,Jtest能够为开发人员节省大量的时间并防止了错误。由于能够自动执行白盒测试的各个步骤,Jtest对开发人员来说是非常实用的,为了保证质量可以经常执行这一综合性测试。更进一步,使用测试生成系统技术产生的测试输入,Jtest使得白盒测试比手工测试更精确更有效。
白盒(构造)测试验证对一个类的非预期输入不会导致程序的崩溃。为执行白盒测试,您需要设计和执行根据类的内部结构编写的测试输入,检查是否存在会导致类运行失败的任何可能的对类的使用,以及是否存在某些编程缺陷可能会导致代码更容易出错。白盒测试能否成功的关键取决于测试输入的能力,是否能够尽可能全面地覆盖类的方法,并找出引起未捕捉到的运行时异常的输入。
尽可能早的防止和检测构造问题对Java软件开发来说更为关键。在大多数语言(如C和C++)中,一个非法程序操作常常导致程序的突然中断。Java相对来说提供了一种非常简单的机制来捕获运行时出现的异常并让程序继续运行,这种机制的设计可以简化对系统和其它服务调用的处理。另一方面,一个非法操作引起运行时异常确实指出了程序中的一个错误。捕捉它们并让程序继续运行通常比C++中的突然中断更有问题。带有问题的程序将继续运行是乎好象没有问题出现过,但极有可能进入一种矛盾状态,并产生不准确的结果或破坏它所存取的资源。
虽然白盒测试是保证类和应用质量的一个关键步骤,但手工执行的难度通常会使开发人员望而却步或草草了事。有效地执行白盒测试需要我们能够确定要完全检查被测类那些测试用例是必需的,这对于手工测试来说是太难了。目前的研究表明,典型的公司只测试了其开发的30%的代码,而其余的70%从来没有被测过。一个原因是编写能够测试很少执行的路径或极端的条件的测试用例很困难。例如,一个典型的1万行代码大约有1亿条可能的路径;手工编写能够执行所有路径的测试输入是不可行的或者说几乎是不可能的。
Jtest使用独特的技术完全自动化白盒测试过程。Jtest分析每个被测类的内部结构,自动设计和执行能够完全测试类的结构的测试用例,然后确定每个测试输入是否会产生一个未捕获的运行时异常。对于检测到的每个异常报告一个错误信息并提供一个导致错误的栈轨迹和调用序列。
使用Jtest进行黑盒测试比使用任何其它工具更简单(也更有效)。Jtest的专利技术通过分析类的字节码自动生成一组核心输入;这些输入经过精心设计能够达到尽可能高的代码覆盖。由于自动生成的输入的设计目标是覆盖类的方法,而非验证其定义,因此用户可能需要增加自己的测试用例。(这一点是可以理解的,自动技术是针对语法的,机器并不能理解人的真正意图。)
用户定义的输入可以直接添加到树形表示的测试用例中,其中节点代表方法的每个参数或者能够存贮在全局或局部存储库中的常量和方法;在这里,输入可以方便地加入到任何方法的参数中。当测试进行时,Jtest自动执行所有的输入并以简单的树形表示显示相应的输出。在以后的功能测试或回归测试测试中出现错误时,Jtest会自动通告用户。
由于Jtest自动生成了一组很棒的核心输入,大大减少了开发人员和测试人员需要建立的测试用例的数量,并且能够比手工设计覆盖程序中更多的代码--多快好省。
黑盒(功能性)测试检查一个类的行为是否符合其功能说明。为了执行黑盒测试,您需要建立一组输入/输出关系,它们能够测试是否准确实现了类的功能说明。对说明文档中的每一项至少需要有一个测试用例,最好这些测试用例还能测试每一项说明的各种边界条件。测试用例准备好后,您执行它们并验证是否产生了准确的结果。
如果您的类代码中含有按合同设计(DbC)格式的说明信息,Jtest能够完全自动化黑盒测试过程。如果没有,Jtest也能比手工做黑盒测试更容易更有效。
DbC是一种形式化方法,使用注解在代码中加入说明信息。基本上,使用一种描述软件合同的形式语言能够明确表达代码说明。这些合同说明了这样的需求:
· 在调用一个方法之前必须满足的条件(前置条件)。
· 在调用一个方法之后必须满足的条件(后置条件)。
· 在执行中的说明点必须满足的断言。
Jtest读取类代码中用DbC语言定义的说明信息,然后自动基于这些信息开发测试用例。Jtest设计按照下面的规则设计黑盒测试用例:
· 如果有后置条件,Jtest建立验证是否满足这些条件的测试用例。
· 如果有断言,Jtest建立试图使断言失败的测试用例。
· 如果有不变条件(即应用于类的所有方法),Jtest建立试图使不变条件失败的测试用例。
· 如果有前置条件,Jtest试图找到能够走通前置条件中所有路径的输入。
· 如果被测方法调用的其它方法中包含已说明的前置条件,Jtest确定被测方法是否能将不允许的值传递给其它方法。
关于Jtest如何自动建立和执行验证类功能性测试用例以及DbC说明如何帮助Jtest的黑盒测试的详细描述,参见"利用按合同设计方法自动化Java软件和部件测试"。
如果您没有使用DbC,Jtest也能帮助您建立黑盒测试用例。您可以使用Jtest自动生成一组测试用例作为黑盒测试用例集合的基础,然后通过加入自己的测试用例扩展它们。
可以有多种加入测试用例的方法。例如:
· 直接在表示每个方法参数的树节点中键入方法的输入。
· 设置全局或局部的常量和方法,然后加入到任何方法参数。
· JUnit格式的测试类作为测试用例。
如果一个类引用外部资源,您可以进入自己的桩函数或让Jtest调用实际的外部方法。当测试运行时,Jtest使用任何可以得到的桩函数,自动执行输入,并以树形表示显示对应这些输入的输出结果。然后您可以观察输出结果并验证。当说明和回归测试错误出现时,Jtest能够自动通报。
执行准确的回归测试是保证软件质量和可靠性的另一必要步骤。回归测试即使用前面测试所用的同一组输入和测试参数测试修改过的代码,它是保证一个类在修改后不会引入新的错误或者检查是否成功地排除了错误的唯一途径。每次一个类被修改或用于一个新环境,都应该进行回归测试以保证类的完整性。
Jtest的回归测试使得您能够在类一级执行回归测试,这意味着您能够更早地运行测试用例以监测代码的完整性。Jtest完全自动执行回归测试有关的所有步骤。假使用户没有说明正确的输出,Jtest能够记忆前面的输出结果,并在每次测试时进行比较,当任何输出发生变化时报告一个错误。当然,如果用户指定正确的输出结果,在回归测试时Jtest使用这些值作为参考结果。为了使自动的回归测试尽可能快速准确,Jtest在测试一个或一组类时自动保存所有的测试输入和设置,然后将测试加入到Jtest的菜单选项中。其结果是,用户执行回归测试所需要的只是在测试菜单中选择一个合适的测试,然后按下开始按钮。您还可以将批处理模式的Jtest集成到夜间建立中,保证回归错误能够及时发现和纠正。
Jtest的编程标准可以分成以下几类:
· 未使用代码
· 初始化
· 面向对象编程
· 命名约定
· JAVADOC注释
· 移植性
· 优化
· 无用信息回收
· 线程和同步
· EJB
· 类指标
· 项目指标
· 国际化
· 安全
· Servlets
· 杂项
另外,Jtest包括一组编程标准帮助您使用DbC在代码中加入说明信息。每个Jtest编程标准有一个违规严重性程度的级别,最有可能引起错误的是1级,最弱的是5级。缺省设置下,Jtest报告1-3级违背编程标准的情况。您可以打开和关闭单个、一级或一类编程标准。这种定制能力使得Jtest能够更适合您的团队或项目,减少不必要的信息。
您可以使用RuleWizard建立和执行定制的编程标准,以适应您的编程风格、开发队伍和整个项目。您在RuleWizard中用图示化表达模式设计和修改编程标准("规则")。建立规则只需点击鼠标,在类似流程图的表示中加入规则建立元件,然后用对话框作必要的修改。不需要有关语法分析的知识。在测试时,Jtest就象内建的编程标准一样对待定制标准。
例如,假如您发现您在if语句的条件中经常误用赋值等号(即应该写if (a==b)而写了if (a=b)),您可以建立一个编程标准"避免在if语句的条件中出现赋值等号"。
通过提供一个好用而且适应性强的方法实现即使是最复杂和独特的Java编程标准,Jtest帮助您执行许多软件开发专家相信是最有效的软件质量保证方法:错误防止或预防。在编写代码时防止尽可能多的错误引入,不仅能够减少耗费在发现和纠正错误上的时间、工作和费用,还能极大地降低一些错误躲过测试的风险。
Jtest在静态分析时自动度量类和项目的有关指标。如果任何指标超出了预设的"合理"范围(您可以设置),Jtest将报告一个静态分析违规信息,这些信息将对违规做出解释并报告问题的准确位置,游戏您可以方便地决定需要简化那些代码以及如何改变。Jtest提供一个关于每个类和每个项目的所有指标的汇总报告。
另外,Jtest帮助您跨项目跟踪指标,保存每次测试的项目指标,并能够图示化地显示项目中下列指标的变化:
· 所有类文件的字节总数。
· 类的数目。
· Java源文件的数量。
· 类的代码总行数
· 包的数量。
· 私有类数量。
· 保护类数量。
· 公有类数量。
1.4 使用说明
1.在windows安装步骤:
1)双击jtest自解压文件jtest_win32.exe
2)按提示步骤进行,一直到结束安装
3)替换规则
将..\ParaSoft\Jtest4.5\jrules下的规则用我们制定的替换掉。
Jtest的界面分为ClassTesting UI和Project Testing UI两种
ClassName 面板用于指定所要测试的类,测试人员或者选择或则输入待测试的类具体的位置和名称。推荐测试人员使用browse按钮,选择测试类的方法。这样做的好处在于,当你选定一个测试类时,工作路径被设定在类package 的根目录下。
Test Progress面板显示下列的测试进程和覆盖率信息:
StaticAnalysis:显示静态分析的测试进程。图中,“Numberof rulesanalyzed ”表示所采用的静态分析法则的数目。
DynamicAnalysis:显示动态分析的测试进程。
Numberof Test Cases Executed:显示所执行的全部测试案例的数量
Automatic显示所执行的测试案例中,由Jtest自动产生的那一部分。
UserDefined 用户自己定义的那一部分测试案例
Numberof Outcome comparisons:显示在黑盒测试和回归测试当中经对比测试类结果的数目
TotalCoverage:显示Jtest所达到的累积的测试覆盖率
Multi-conditionBranch显示所达到的复合条件分支的覆盖率
Method显示所达到的方法的覆盖率
Constructor显示所达到的构造器的覆盖率
ErrorFound 面板用于显示Jtest在测试过程中所发现的错误信息,并且允许测试人员执行多种操作,以帮助理解和定制结果。
StaticAnalysis Errors 静态分析时发现的错误数目
所违反的规则名(规则的ID显示在圆括号中);所违反的规则的信息,为了禁止显示此类信息或是查看相关的规则描述,则需要用鼠标右键点击此节点,然后从出现的快捷菜单中选择适当的命令。错误出现的文件/行数,右键点击该节点,从弹出的快捷菜单中选择适当的操作命令,便能够来查看或编辑相关的源代码。
Uncaught Runtime Exception 是Jtest在执行动态分析时所发现的,未捕捉的Runtime异常错误的数量,每个未捕捉的runtime异常被一个完整的堆栈轨迹所跟随,一个案例的输入也导致的此种异常。
堆栈轨迹信息,为了查看或是编辑源代码,需要用鼠标右键点击此节点, 然后从出现的快捷菜单中选择适当的操作命令(如果文件和行数信息失,请根据调试信息重新编译类文件)
;定义测试案例的输入值,对于自动测试案例,输入是thecalling sequence
;对于用户自己定义的案例,则是每个变量的输入。
Specification&RegressionException是Jtest在执行动态分析时所发现的规范错误以及回归错误。将此时运行与早些时候的运行或是由用户指定的运行所产生的测试案例的结果加以比较,此列错误也就由此而得以发现。
规范和回归错误的发现
;定义测试案例的输入值,对于自动测试案例,输入是thecalling sequence;对于用户自己定义的案例,则是每个变量的输入。
Controls面板允许测试人员指定工程测试过程中使用到的基本参数,以及有关一个工程测试的报告基础数据。
SearchIn:指明Jtest开始测试的位置。
Filter- In:告诉明Jtest只查找和测试与给定表达式匹配的那些类。用‘*’字符来匹配0或其他更多的字符。
Results面板显示Jtest在一个工程测试过程当中所发现的错误信息,此外它还允许测试人员执行许多用以帮助理解和定制化结果的运行操作。
publicclass SimpleClassTest1 {
/**
* 判断输入,当输入等于0或9时,函数输出0当输入等于6时,函数输出11,
* 输入为其他情况时则输出8;
**/
public static int Test(int input) {
switch (input) {
case 0:
case 9:
return 0;
case 6:
return 11;
default:
return 8;
}
}
/**
* 判断输入的两字符串,当前个字符串以后一个开始并包含后一个字符串时,
* 函数返回为true,否则返回false。
**/
public static boolean Contains(Stringstr1,String str2)
{
for( int i=0;i if(str1.charAt(i)!=str2.charAt(i)) return false; return true; } /** * 将输入的两整数相加,函数返回其相加的结果。 **/ public static int add(int a,int b) { return a+b; } } 步骤: 1.在桌面上点击Jtest程序图标 2.打开ClassTesting UI 3.按Browse按钮,并定位到例子程序SimpleClassTest1.class 4.点击start 1. 2. 5.经过少许等待,Jtest便能够发现SimpleClassTest1中的问题,并且把问题报告到Errors Found Panel中: 6.进入问题处看一下,双击bug处 7.如何查看Jtest自动生成的用例 在Test Progress 面板中点击鼠标右键,进入Viewtest case选项 手工输入值 1. 增加输入到静态方法 打开Class按钮,并在弹出的classtest parameters窗口依次打开Dynamic Analysis> Test CaseGeneration> User Defined> Method Inputs. 然后打开add,右键点击intARG1,选择Add Input Value,输入16,按回车。 同样的方法,增加int ARG2,输入其值为28。 2.查看和合法化用户自定义的输入以及输出结果的步骤如下: 点击View按钮,打开ViewTest Case窗口 依次打开User Defined Test Cases>Method Inputs> add> Test Case 1. 完全展开Test Case 1 为了申明输入产生的结果是正确的,右键点击OutComes节点,在弹出的快捷菜单中选择Set All Correct。 3.增加对象类型的输入 打开Class按钮,并在弹出的classtest parameters窗口依次打开Dynamic Analysis> Test CaseGeneration> common 右键点击Input Repository,在弹出的快捷菜单中选择AddMethod项 4.在AddMethod窗口中,增加方法申明: 在窗口的Decl区域输入:java.util.VectorCreateVector() ;在窗口下方的空白处输入方法主体: java.util.Vectorv = new java.util.Vector (); for (int i = 0; i < 5; i++) { v.addElement (new Integer(i*2)); } returnv; 选择Option>Save储存输入的方法。 选择Option>Quit 退出AddMethod窗口。 如果测试中使用到程序接口方法的输入类型是vector时便可以直接使用CreatVector()的方法来建立。 在Jtest的ProjectTesting UI,测试人员能够自动地测试包含在任何目录、或是jar文件、zip文件下的所有的类文件,而且整个过程仅仅是简单的一次点击。 举个简单的例子: 打开Jtest,点击project按钮,在弹出的projecttesing ui窗口中点击browse按钮,并定位到相应目录。 点击The Project tools bar上的start按钮开始测试。 测试后弹出结果 1. 用“jtest规则设置”下的jrules文件夹覆盖自己本机同名文件夹。把自己本机的brules文件夹清空,打开jtest,按照下图对jtest自带的内嵌规则进行设置。设置方法:根据需要在jtest上点击“Project(Class)”或“global”“Rules”,在弹出的对话框(如下图)中选择 2. 图中没有点开的目录中,如果其目录名前的数字没有出现减号(如[5],[4],[2],[1])表示其下的规则都要选中。 3. 如果是[1-1],[16-16],[10-10],[11-11],则表示全部不要,即点空。 4. 其他[2-1],[10-2],[9-2]就按图示选择即可。 注意图中第一行的“Severity LevelsEnabled”下的根据需要选择,目前选前三级;“Built-inRules”的个数是“73-49”;“UserDefined Rules”的个数是144;总之设置的时候防止选错,注意一下各个标题前面的数字。 一. Jtest和开发工具集成:打开Jtest,在Tools菜单下选择IDEIntegration,就可以与各种开发工具集成,这样就可以在开发工具中直接调用Jtest进行测试。只需如上所述设置规则。 二. 如果不跟开发工具集成,建议使用Project Testing UI,可以一次运行所有的class文件。在工具栏点“Class”或“Project”选择用ProjectTesting UI还是Class Testing UI。以ProjectTesting UI为例:点开工具栏“Project”或“global”“Rules”如上所述设置规则;在下图所示的classpath和sourcepath中分别设置引用包路径和源文件路径。1.4.3.1 白盒的测试
1.4.3.2 黑盒的测试
1.4.3.3 回归测试
1.4.3.4 规则设置