JUTA_一个Java自动化单元测试工具_严俊
java 单元测试方法
java 单元测试方法Java 单元测试方法在软件开发中,单元测试是一项重要的实践,能够帮助开发人员在代码实现过程中发现潜在的问题,并确保软件在不同环境下正确地运行。
本文将介绍Java单元测试方法,并逐步回答与该主题相关的问题。
1. 什么是单元测试?单元测试是一种针对软件中最小可测试单元进行测试的方法。
它验证代码的功能是否按照预期工作。
单元测试的目的是在尽可能小的范围内检查代码,以减少问题的出现并提高代码质量。
2. 为什么要进行单元测试?单元测试有以下几个重要的原因:- 保证代码的正确性:通过验证每个单元的正确性,可以提前发现和修正潜在的问题,确保代码按照预期工作。
- 改进代码设计:单元测试可以帮助开发人员发现代码的缺陷和不足之处,并优化其设计。
- 方便重构:单元测试可以保证在对代码进行重构时不破坏其原有的功能,并且可以确认重构后的代码是否仍然正确。
- 提高开发效率:通过自动化执行单元测试,可以节省时间和精力,并提高代码质量,减少调试时间。
- 支持持续集成:单元测试是持续集成的重要组成部分,确保每次代码提交都经过测试。
3. 如何编写单元测试?编写好的单元测试应该满足以下几个要求:- 独立性:每个单元测试应该相互独立,不依赖于其他测试或外部资源的状态。
- 可重复性:每次执行单元测试的结果应该是可重复的。
- 可读性:单元测试应该容易理解和阅读,以便于其他开发人员快速了解代码的功能。
- 全面性:单元测试应该覆盖验证代码的所有情况,包括边界条件和异常情况。
- 快速性:单元测试应该能够快速执行,以便频繁运行。
4. 常用的单元测试框架Java中有多个流行的单元测试框架。
以下是一些常见的单元测试框架:- JUnit:JUnit是Java中最流行的单元测试框架之一。
它提供了一组用于编写和运行单元测试的类和注解。
- TestNG:TestNG是一个全功能的测试框架,相对于JUnit具有更多的功能,包括测试参数化、测试组和配置灵活性等。
java单元测试方法
java单元测试方法
Java单元测试是一种测试方法,它用于测试Java代码的单独功能或模块,以确保其正常运行。
Java单元测试通常使用JUnit框架进行测试。
在Java单元测试中,测试用例通常按照一定的顺序排列,并在每个测试用例中执行一些特定的Java代码。
这些测试用例可以通过JUnit框架进行自动化测试,并在测试结果中提供详细的报告。
Java单元测试可以提供以下的好处:
1. 提高代码质量:Java单元测试可以及早检测代码中的错误,从而提高代码的质量。
2. 减少代码维护成本:Java单元测试可以帮助开发人员快速发现代码中的问题,从而减少代码维护的成本。
3. 提高开发效率:Java单元测试可以帮助开发人员快速发现问题并进行修复,从而提高开发效率。
4. 提高软件可靠性:Java单元测试可以帮助开发人员及早发现软件中的问题,并进行修复,从而提高软件的可靠性。
总之,Java单元测试是一种非常重要的软件测试方法,它可以帮助开发人员提高代码质量、减少维护成本、提高开发效率和提高软件可靠性。
- 1 -。
JUTA-一个Java自动化单元测试工具-严俊.doc
JUTA-一个Java自动化单元测试工具-严俊JUTA:一个Java自动化单元测试工具严俊1郭涛2阮辉1玄跻峰3(中国科学院软件研究所北京100190)(中国信息安全测评中心北京100085)(大连理工大学数学科学学院辽宁大连116024)(junyan@)JUTA:An Automated Unit Testing Framework for JavaYan Jun1,Guo Tao2,Ruan Hui1,and Xuan Jifeng31(Institute ofSoftware,Chinese Academy ofSciences,Beijing100190)2(China Information Technology Security Evaluation Center,Beijing100085)3(Schoolof Mathematical Sciences,Dalian University of Technology,Dalian,Liaoning116024)set of test cases satisfying the test criterion such asstatement coverage.The test set typically has small number of test cases that are all executable.Inaddition to test generation for dynamic testing,it can also be used in static testing.JUTA can revealcertain kinds of errors from the source code automatically if the user provides proper assertions todescribe the errors.The experimental results show that this tool is efficient for both dynamic andstatic testing.Key words Java unit testing;dynamic testing;static testing;program analysis;symbolic execution摘要描述了一个Java自动化的单元测试工具JUTA.JUTA首先调用工具Soot解析单个Java方法的源码,并将源码解析成一个控制流图.在此基础上,采用符号执行的方法分析控制流图上的路径.工具能够自动地产生满足覆盖率标准的程序的测试用例.这种方法产生的所有测试用例都是可执行的,并且一般来说具有较小的测试用例数.如果用户能够合理地给出描述程序错误的断言,框架JUTA能够自动地检查源码中部分特定类型的错误.实验结果表明工具对Java单元代码的动态测试和静态测试均能在可接受的时间内给出有效的结果.关键词Java单元测试;动态测试;静态测试;程序分析;符号执行中图法分类号TP311的控制转移都得到了覆盖).由于在控制流图模型中,语句与节点相对应,语句覆盖意味着测试路径覆盖所有的节点.同样地,分支覆盖就是所有的测试路径覆盖了控制流图中所有的边.1.2基于路径的程序测试程序中的一次完整的执行过程对应控制流图中的一条完整路径.但是,并不是所有的完整路径都代表程序中的一次运行过程.这是因为可能不存在输入数据使得程序按照该路径执行.这样的完整路径称为不可行路径(infeasible path),否则称为可行的(feasible)[2].例如,在例1中,路径p1执行的语句如图2所示(符号“@”后的表达式表示程序执行该逻辑判断为真的分支).易知,程序执行到第2个判断语句时,表达式(i+2×j<5)不可能满足,程序控制流图中的分支S3-S4不可能被执行到.那么,路径p1是一条不可行的路径.good=TRUE;@((i>2)&&(j>3));j=j-1;@(i+2×j<5);good=FALSE;Fig.2Pathp1.图2路径p1由于控制流测试准则都是基于控制流图中的测试路径来定义,很自然地,我们可以采用如下方法来生成测试用例:首先从控制流图中找到一组路径满足覆盖准则,然后从每条路径中找出各变量的一组初始值使得程序能够按照路径执行,这些初值就构成了测试用例集合.一般来说,一个自动测试用例生成(automated test case generation)系统主要可以分成3个部分[3]:1.程序分析器(program analyzer),其主要工作是把程序转化成容易处理的中间模型(一般就是我们前面提到过的控制流图);2.路径选择器(path selector),如何选择路径满足我们的测试需求(比如覆盖准则);3.测试数据生成器(test data generator),如何从测试路径中得到我们需要的测试数据.在实际开发中,程序分析器也被称为前端(frontend),后两部分合起来被称为后端(backend).这样的自动测试生成的系统主要用于程序的动态测试,即采用测试用例测试被测程序.与动态测试对应的静态测试方法,其框架与测试生成大体相同.主要的不同指出在于其输出并不是测试用例,而是直接报告程序是否包含某类错误,或者给出能检出某类错误的具体的测试数据.由于程序测试的需求众多,实际的测试系统尤其是商用系统,可能还包括一些其他的辅助模块,比如测试脚本的自动生成器等.1.3路径分析方法不可行路径给自动化测试带来了一个难题,我们不可能简单地通过从程序控制流图的信息中路径来选择测试用例,在测试用例选择时必须分析数据流的信息.为了精确地分析控制流图中一条完整的路径,我们可以采用符号执行(symbolic execution)[4]的方法.所谓符号执行,相对于普通的程序执行来说,就是程序并不真正用数值来替换程序的变量,而是用一组关于初始值的表达是来表示程序中出现的项.用符号执行加约束求解进行程序分析的基本思想是:采用Hoare逻辑可以将程序路径表示成{P} Q{R},其中P是程序的前置条件(pre-condition.执行程序前需要满足的条件,或者称为前断言),R是程序的后置条件(post-condition,程序执行后需要满足的条件,或者称为后断言).假定在程序的符号执行过程中由{P}Q可以推导出约束条件c1∧c2∧cn,则应该有c1∧c2∧…∧cn※R.在一般的测试中,如果后断言永真,那么可以对约束条件c1∧c2∧…∧cn求解,可以得到变量的初值,从而得到测试用例.另一方面,我们可以对约束c1∧c2∧…∧cn ∧瓙R求解,如果有一组解满足这一约束,说明存在一组输入使运行程序的结果和规范不符.如果程序的规范正确,则程序中必定包含错误.对于不包含函数调用代码来说,程序的语句可以分成3类:1)动作(action),也就是赋值语句;2)判断语句(predicate),也就是一个逻辑表达式;3)其他不影响变量的表达式,如控制台打印语句System.out.println.我们用一个具体的例子说明符号执行的原理.考虑图2的路径p1,如果i和j的初值为i0和j0,我们可以自顶向下依次执行这段程序,用程序的赋值语句替换判断语句,最后得到一个只含有判断语句的约束集合{i0+2×(j0-1)<5;(i0>2)&&(j0>3)}.这个集合就是程序初值的约束.由于这个约束集是不可满足的,所以路径p1 是不可行的.关于符号执行的具体细节请参考文献[2,5-6].符号执行的好处是能够精确地分析程序的行为,但它的缺点也是显而易见的.由于符号执行方法过于依赖源代码,并且需要消耗较大的计算资源,因1842计算机研究与发展2010,47(10)而无法精确分析带有很多模块调用(特别是当这些子模块代码不可见的时候)的程序.同时,程序需要能够用约束精确模拟复杂程序结构,比如指针和数组的执行,这是一件很困难的事情.最后,为了保证分析的精确性,符号执行需要有一个能力非常强的完备解法器(complete solver,就是说,只要约束有解,解法器必然能够给出一组解).针对不同的程序,这个解法器可能需要处理位操作等复杂的约束.这一点也限制了符号执行方法的使用.工具JUTA 中采用较为简单的方式在工具的处理能力和精确度之前作了一个平衡.我们将程序中的表达式限制为布尔逻辑和线性数值约束两种类型,并且将程序的外部调用抽象成简单的赋值语句和后置断言.具体内容见本文第2节.2工具JUTA的设计与实现本节将详细介绍JUTA工具的流程以及工具的模块组成,同时对每一个模块给出其功能以及简要的描述,主要目的是为工具提供一个整体的框架描述.2.1工具流程为了便于理解源程序需要对程序的源代码进行一定的处理.首先要做的就是编译分析,包括语法语义错误的检查、建立中间表示(intermediate representation,IR)并生成控制流图等.同时为了以后的分析,我们还需要识别出源代码中的循环,并对循环进行处理,建立一棵循环控制树.这部分通常成为前端处理.有了前端处理的程序结构和数据信息,我们就可以通过算法遍历控制流图,得到一系列的路径,并通过符号执行和约束求解来分析这些路径,对其可行性进行判断,对于可行的路径为其生成测试数据,最后收集这些测试数据就得到了满足某些性质的目标测试数据集.因而,从整体上工具分为两个部分:前端处理和后端分析,其整体结构如图3 所示:Fig.3Framework of JUTA.图3JUTA的框架目前,工具JUTA实现了两方面的功能:静态测试与动态测试.本文1.2节曾指出,这两种测试方法可以公用相同的前端,主要区别在于工具的后端.接下来我们将按照功能分别介绍工具的各模块.2.2工具输入工具输入包含两部分.首先是被测的Java源码.源码中包含被测Java代码的单个方法.由于工具JUTA的主要功能是完成单元测试,所以,工具将丢弃方法中的外部调用.用户在测试时,需要手工将重要的外部调用替换成赋值语句或者约束表达式.例如,对于语句y=foo(x),假定外部调用foo将y的值改变为foo x,并且这个值的范围是[lb,ub].那么可以将这行代码替换为: y=foo x;assert(lb< =foo x&&foo x< =ub);另一部分的输入是一些描述性质的断言以及断言的插入位置.具体请参见本文2.4.2节.2.3前端处理前端分析整体上相当于一个编译器的前端,功能上相当于一个不产生目标代码的编译器.在这一部分我们借用的是Java分析优化工具框架Soot[7]的编译分析功能.Soot是一个功能很强大的分析框架,融合了编译前端以及分析器的各种功能.工具JUTA的前端在Soot框架下扩展其功能,产生后端分析所需要的中间结果.在JUTA中,我们主要使用了Soot的语法语义检查、中间表示、循环控制分析以及控制流图1843严俊等:JUTA:一个Java自动化单元测试工具生成等模块.接下来简要介绍这几个模块的功能.2.3.1语法语义检查模块该模块主要完成源代码语法语义的检查,确保给定的输入程序是没有语法语义错误的,同时建立一棵等价于源程序的抽象语法树.2.3.2中间代码生成模块这部分通过遍历抽象语法树,对各种语句进行处理,产生中间表示,便于以后的分析和处理.Soot 提供了4种中间表示形式:Baf,Jimple,Shimple和Grimp.工具JUTA使用了Soot的Jimple中间表示.Jimple是一种简单的带类型的3地址表示形式.例如图4为Java源码与对应的Jimple代码.图4(a)所示的一段简单的Java代码,经过Soot翻译后得到图4(b)所示:public static intfunc(intx){inty= -1;if(x>0)y=1;elsey=2;returny;}public static intfunc(int){ intx,y,temp$0,temp$1; x:= @parameter0:int;y= -1;ifx>0 goto label0;goto label1;label0:nop;temp$0=1;y=temp$0;goto label2;label1:nop;temp$1=2;y=temp$1;label2:nop;returny;(a) (b)Fig.4Java source code and the corresponding Jimplecode.(a)Java source and(b)Jimple code.图4Java源码与对应的Jimple代码.(a)Java源码;(b)Jimple代码2.3.3控制流图建立模块本模块通过遍历中间表示的列表,将中间表示序列划分为基本块,控制流图即是以基本块为节点的有向图,描述了源代码中的控制流.工具JUTA 使用Soot中的Brief Block Graph,只为源代码中基本的控制流提供支持,目前无法处理异常(exception).2.3.4循环控制分析模块这一部分主要是分析控制流中的循环,Soot中将每一个循环抽象成一个对象,每一个循环都存储自己的循环头部以及循环体.一般来说,结构化的序中的循环分成3类,孤立循环(single loop)、嵌套循环(nesting loop)以及串联的循环(concatenatedloop)[8].我们可以建立一个抽象的循环控制森林,森林中每一个节点是一个表示循环的对象,用来描述循环之间的关系.循环A是循环B的子节点,当且仅当循环B内嵌在循环A之中.当被测程序中不包含串联循环时,循环控制森林退化为循环控制树.2.4后端分析本节将介绍工具的后端.考虑到动静态测试的不同之处,我们将分别介绍动态和静态测试的功能模块,之后对两者进行一个比较.2.4.1动态测试后端动态测试的目标是生成一组满足覆盖率的测试数据.所以,动态测试的后端需要分析前端处理后得到的数据信息(包括中间表示、控制流图以及循环控制树),根据路径产生策略以及覆盖准则产生满足要求的路径,并且通过分析路径的可行性得到测试数据.这一部分有以下4个模块:路径生成、路径转换、路径分析以及路径选择.1)路径生成模块这一模块将分析由前端处理得到的控制流图,并抽取出一系列的路径.这些路径可以用基本块的编号序列表示.路径的产生过程是通过遍历控制流图来得到的.由于程序中可能有循环,那么,从图中可能抽取出无限条路径.为了产生有限条测试路径,我们可以限制循环次数或者限制路径的长度(路径表示中基本块的个数).在工具JUTA中可以通过参数来选择使用的路径限制策略.路径产生是一个遍历控制流图各顶点的过程,在图的遍历算法中有两种常见的策略:深度优先遍历(DFS)和宽度优先遍历(BFS).当采用BFS算法时,是按照路径长度由短到长的次序生成路径,所以在队列中需要存储最多两层的中间节点,当路径长度限制比较大或者循环次数限制值比较大时,队列中需要存储很多的节点.在使用DFS算法时,由于优先考虑循环的退出节点,在栈中存储的元素数目比较少,但是生成的最终路径不是按照由短到长的顺序.而且很多路径都是由几个相同的基本块所组成.由上述的比较可知,使用DFS占用较少的系统资源,但是在处理过程中,尤其是在CFG包含环时容易陷入一个分支无法跳出,无法快速达到覆盖率指标,比较适用于静态测试;使得BFS能够较快达到覆盖率,但是代价相对较高,适用于在测试覆盖准则指导下的测试生成.工具JUTA的路径生成模块实现了这1844计算机研究与发展2010,47(10)0引言软件质量历来就是学术界和工业界共同关心的问题,因为软件质量问题造成巨大经济损失事件不胜枚举.当前,随着信息技术的迅速发展,特别是互联网技术的广泛应用,Java技术以其通用性、平台移植性、安全性等特征,吸引了众多软件开发者,在各个重要的行业部门得到了广泛的应用.因此,如提高软件质量,尤其是提高应用广泛的Java程序的可靠性,长期以来一直是一个非常重要的研究课题.软件测试是提高软件质量的重要手段.优秀的软件开发机构把40%的工作量花在软件测试上,软件测试费用则占到了软件开发总费用的30%~50%,而对于一些要求高可靠性、高安全性的软件,测试费用已经抬高到了整个软件项目开发所需费用的3~5倍.单元测试是软件测试的早期阶段,这种测试方法主要测试程序的单元函数或者类中的方法,其主要原理是对源代码中的控制结构和处理过程等进行分析,检查程序内部处理是否正确,包括语句结构、分支和循环结构等.由于单元测试需要分析源代所以测试的代价往往比较高.目前,在工业界,单元测试大多仍然是靠人工完成的,如手工设计测试用例、人工审阅代码等,不但十分繁琐,而且测试质量与测试人员的主观经验紧密相关.随着计算机软硬件规模的不断发展,以人工为主的测试方法已经无法满足测试的需求.目前,采用计算机辅助的自动化软件测试技术成为软件工程中一个活跃的研究领域.本文介绍一个Java自动化的单元测试工具JUTA(an unit testing and analyzing tool for Java).与Junit等传统测试框架不同,JUTA提供了一系列的精度和自动化程度较高的技术来生成测试用例以及检查代码中的错误,以提高测试的自动化程和效率.1预备知识本节将简要介绍JUTA采用的控制流和数据流分析技术.1.1控制流图形式化地说,控制流图(control flow graph, CFG)是一个有向图G= N,E,s,f ,其中N代表节点的集合,E代表边的集合,s和f分别表示控制流图的起点和终点.图中每个点n∈N代表程序中的一系列顺序运算(即这些语句在程序执行过程中要么全部都执行,要么全部都不执行),或者说是一个基本块(basic block);而每条边,e=(ni,nj)∈E, 代表从节点ni到nj的一个转移.用流图作为程序结构的模型时,程序的运行过程可以用流图中的路径来刻画.控制流图中的一条执行路径p代表一个执行序列p= n1,n2,…,nm ,其中m是路径的长度, (ni,ni+1)∈E(1≤i<m).一般来说,程序的执行必须从起点s开始.我们称n1=s的这条路径为部分路径(partial path).如果n1=s并且nm=f,我们称p是程序的一条完整路径(complete path).在下文中,如无特殊说明,我们所说的程序路径都是完整路径.例1.图1为一段简单的代码及其控制流图.函数foo根据输入i和j的值计算参数good的值并返回.从控制流图上易知程序有3条从起点S到终点F的完整路径:p1= S,S1,S2,S3,S4,F ,p2=S,S1,S2,S3,F ,p3= S,S1,F .public intfoo(inti,intj){*S*intgood=TRUE;*S1*if((i>2)&&(j>3)){*S2*j-- ;*S3*if(i+2*j<5)*S4*good=FALSE;}*F*returngood;}Fig.1 A piece of example code.图1一段示例代码对于基于控制流图的结构测试来说,主要的测试方法就是找到一系列的可行测试路径,这些路径的输入数据就是测试用例.例如在例1中,{i=3,j=4}就是对应于路径p2的一个测试用例.测试人员通过执行这些测试用例来检查程序的错误.显然,由于程序代码的复杂性,通过枚举所有的测试路径来测试程序是不现实的.为了减少测试的代价,人们定义了一系列的测试覆盖准则(coverage criterion),作为测试的标准来限制测试集的大小[1].最简单的控制流覆盖准是语句覆盖(statement coverage,即在软件测试过程中,只有当程序中的所有语句都得到了运行,才能称该测试是充分的)和分支覆盖(branch coverage,即要求在软件测试过程中,所有1841严俊等:JUTA:一个Java自动化单元测试工具两种策略,用户也可以用参数指定所使用的遍历策略.在默认情况下使用的是深度优先.2)路径转换模块前面1.3节中介绍过,对于不包含函数调用代码来说,程序的语句可以分成3类.而我们主要关注其中两类语句,即赋值和判断.路径转换模块将采用基本块的编号序列表示的路径,根据基本块对应的Jimple中间表示,翻译成一些简单的赋值和判断语句,方便下一步的路径分析.3)路径分析模块这一部分主要是用来对产生的路径进行分析.张健等人在文献[2,5-6]中提出了基于符号执行以及约束求解的路径分析方法,并给出了一个工具EPAT用于判断C程序路径的可行性.目前,EPAT 支持布尔逻辑表达式和线性数值约束表达式及其混合,同时还支持数组和指针下标的运算.考虑到经过断言插入和路径转换后的路径只包含两类基本的表达式:判断和赋值,从而可以调用EPAT来分析Java程序的路径条件,判断出路径是否可行,并对可行的路径产生测试数据.4)路径选择模块为了采用较少的测试数据测试程序,可以在所有可行路径中选择一些有代表性的路径来测试被测代码.可行的选择标准就是覆盖准则,例如语句覆盖.在这种测试方法中,我们力图用最少的测试数据去覆盖尽可能多的语句或者是基本块.这个问题实际上是一个测试集约简(test reduction)问题.Wang等人指出,这种以覆盖路径中的点或者边为目标的测试约简问题可以采用线性规划方法求解[9].具体到这个问题,由于路径生成模块可能产生的路径数目太多,一般的线性规划工具无法处理这么大规模的问题,工具JUTA通过以下3个步骤来约简测试集.①不可行路径删除.首先要做的就是删掉不可行路径.这一步在我们的前几个模块已经完成,所以可以不用考虑.②删除冗余路径.采用贪心算法来减少可行路径集合的大小,将那些对覆盖率没有贡献的测试路径予以删除.③寻找最优路径集合.可以使用线性规划工具进一步删除冗余的路径,得到一个最小的路径集合.实验结果表明,这个路径约简方法能够得到接近最优的测试集合(参见3.1节).2.4.2静态测试后端静态测试的目标是给出程序是否包含某类错误的一个判断.在原理上,工具JUTA的静态测试与动态测试都是采用路径分析方法,所以静态测试后端重用了动态测试后端的3个模块,即路径生成、路径转换、路径分析.在本文1.3节中指出,可以通过简单的断言来描述程序的错误性质,从而自动地、静态地检查程序的错误.为了便于用于描述程序错误性质,工具在静态测试的后端中的路径分析模块之前增加一个模块,用于在路径中插入断言表达式.当此模块功能打开时,工具JUTA的输出就是满足这些条件的测试路径集合.在工具JUTA中,断言插入模块读入条件表达式,并将这些条件插入到路径的相应位置.目前, JUTA支持在指定的基本块前后加入前置或者后置条件.断言的语法形式是BBID expr Position Mode,其中:①BBID表示基本块的编号;②expr表示描述错误的性质的条件表达式,目前支持线性数值约束与布尔逻辑约束的混合; ③Position表示插入断言的位置有两个选项: pre和post,分别表示插入到基本块之前或者之后;④Mode表示断言插入的模式,有4种选项,F表示在路径中第1次出现该基本块时插入;L表示在路径中最后一次出现该基本块时插入,A表示在所有的基本块的对应位置插入该断言;而当这一项为一个数值i时,表示在该基本块第i次出现的位置插入断言.例2.假定为了测试如下循环程序是否有数组下标越界的错误.*block 14*for(inti=0;i<n;i++){*block 15*read(a[2*i]);}我们在基本块15中发现被测程序对数组a[]下标进行了运算,则可以在基本块15之后加入如下条件表达式(假定数组大小20),描述下标越界: 15(2*i<0‖2*i> =20)post L,然后让工具枚举从控制流图起点到基本块15的部分路径并检查可行性.这样,如果JUTA输出一条可行的部分路径,即存在一条可以执行的输入使得描述错误的断言可满足,则表示程序在基本块15中可能含有数组下标越界的错误.1845严俊等:JUTA:一个Java自动化单元测试工具2.4.3动静态测试后端的不同之处动态测试需要分析完整路径并给出测试数据,而静态测试并不需要给出完整的路径,只需找到包含错误的部分路径即可.因而在静态测试中,路径生成模块给出的路径是以可能出错的基本块为终点的部分路径.另外,静态测试需要一个断言插入模块插入用户定义的断言以检查程序中的错误,而动态测试需要一个路径选择的模块来约简测试集.表1比较了两个后端的不同之处:Table 1Comparison Between the Backends of Static andDynamic Testing表1静态测试与动态测试后端比较Module Static Testing Dynamic TestingPath Generation Partial Path Complete Path Assertion InsertionInsert User WrittenAssertions-Path Selection-Test set reduction3实例研究本文我们将通过部分实例来展示工具的功能. 3.1动态测试动态测试的目标是产生测试用例,并达到测试覆盖率.我们选择了6个方法实例,设置每个循环限制的循环次数上限是3次,覆盖准则是语句覆盖,得到一个可行路径集合 F.然后通过路径选择模块约简得到一个最优测试集合O.表2列出了实验结果,所有实例的运行时间均在1 min以内.这里,圈复杂度(cyclomatic complexity)[10]描述了程序的逻辑复杂度,其定义为v(G)=e-n+2=d+1,。
使用Junit进行单元测试的自动化
使用Junit进行单元测试的自动化单元测试是软件开发中至关重要的环节,它可以帮助开发人员准确地、高效地发现代码中的错误,并确保每个模块的功能都能按照预期运行。
在传统的开发中,单元测试需要手动编写测试用例、执行测试用例、检查测试结果,这个过程繁琐而且容易出错。
为了解决这个问题,自动化单元测试工具应运而生,而Junit就是其中最为知名的一个。
Junit是Java编程语言的一种单元测试框架,它是基于Java语言的自动化测试工具,能够帮助开发人员快速、方便地进行单元测试。
下面,我将就如何使用Junit进行单元测试的自动化进行详细介绍。
1. 安装和配置Junit首先,我们需要安装Junit并进行基本的配置。
你可以从Junit的官方网站下载最新的Junit版本,并将其jar包添加到你的Java项目的classpath中。
在配置完成后,我们就可以开始编写和执行测试用例了。
2. 编写测试用例在使用Junit进行自动化单元测试之前,我们首先需要编写测试用例。
测试用例是指针对程序中的每个功能模块编写的一组输入、输出和预期结果数据。
通过编写测试用例,我们可以对程序的每个功能进行全面而严格的测试。
在Junit中,一个测试用例是一个Java类,并且该类中的每个测试方法对应程序中的一个功能模块。
在编写测试方法时,我们可以使用Junit提供的一系列注解来标识运行规则和预期结果。
3. 执行单元测试在编写完测试用例后,我们可以使用Junit来执行这些测试用例。
Junit提供了一个测试运行器(Test Runner)来管理和运行测试用例。
测试运行器可以帮助我们自动地加载测试类、执行测试方法,并生成测试报告。
除了手动运行测试用例,我们还可以通过使用构建工具(如Ant、Maven或Gradle)来自动运行测试用例。
4. 分析测试结果执行完所有的测试用例后,我们需要对测试结果进行分析。
Junit 会自动为每个测试方法生成测试报告,我们可以查看这些报告来了解每个功能模块是否按照预期运行。
单元测试的测试工具
单元测试的测试工具在软件开发过程中,单元测试是一个非常重要的环节,它有助于确保代码的质量和稳定性。
而单元测试的效率和准确性则取决于所选用的测试工具。
本文将介绍一些常用的单元测试工具。
JUnitJUnit是Java编程语言的单元测试框架,是使用最广泛的单元测试工具之一。
它提供了一组注解和断言方法,方便编写和执行单元测试。
通过JUnit,开发人员可以方便地编写测试用例,并运行这些测试用例来验证代码的正确性。
NUnitNUnit是一个针对.NET平台的单元测试框架,与JUnit类似,但是专门针对.NET开发的特性进行了优化。
NUnit支持各种测试类型,如参数化测试、理论测试等,使得.NET开发人员能够更全面地对代码进行测试。
PHPUnitPHPUnit是PHP语言的单元测试框架,它为PHP开发者提供了一套丰富的工具和功能,来测试PHP代码的正确性。
它支持各种断言方法和测试注解,可以对PHP代码进行全面的测试覆盖。
MochaMocha是一个流行的JavaScript测试框架,用于编写前端和后端JavaScript代码的单元测试。
它支持异步测试、并行测试和多种报告格式,可以方便地集成到各种JavaScript项目中。
PytestPytest是一个简单而强大的Python测试框架,它具有丰富的插件和扩展功能,可以灵活地组织测试用例并生成详尽的测试报告。
Pytest支持多种断言方法和参数化测试,是Python开发者进行单元测试的理想选择。
总结各种编程语言都有适用于自身特点的单元测试工具,选择合适的测试工具可以提高开发效率和代码质量。
无论是JUnit、NUnit、Pytest还是Mocha,它们都是开发人员进行单元测试时不可或缺的利器,帮助开发者更快速、更准确地验证代码的正确性。
单元测试工具的选择要基于项目需求和开发语言,结合实际情况进行权衡,以达到最佳的测试效果。
Parasoft Jtest
七、其它高级功能
使用Jtest RuleWizard自定义代码检测规则 Jtest BugDetective静态数据流分析技术 创建并使用参数化测试用例 基于Jtest的容器测试 生成并执行仙人掌测试(Cactus tests) 使用Excel、CSV文件等数据源添加测试用例 使用Jtest Tracer进行测试 使用命令行界面 Parasoft团队开发测试
4
二、下载与安装
软 件 测 试
Jtest的当前版本支持常见的主流开发平台和系 统。针对不同的平台,Jtest提供了不同的安装 文件。同一安装平台,还提供独立版本和插件 版本两种安装文件,以更好地扩展适用范围。 Windows独立版本 Windows插件版本 Linux/Solaris独立版本 Linux/Solaris插件版本 Mac版本
Parasoft Jtest
王宜政 软件工程
〇、主要内容
Jtest简介 下载与安装 静态测试 动态测试 回归测试 覆盖率分析 其它高级功能 Jtest和Junit的关系 小结
软 件 测 试
2
一、Jtest简介
软 件 测 试
Jtest是Parasoft 公司推出的一款自动化Java编码 标准分析与单元测试工具。Jtest会自动测试任 何Java类或部件,而不需要您写一个测试用例、 驱动程序或桩函数。只要通过简单的几个点击, Jtest就会自动测试代码构造(白盒测试)、测 试代码功能性(黑盒测试)、维护代码完整性 (回归测试)和静态分析(编程标准执行和指 标度量),从而预防未处理异常、函数错误、 内存泄漏、性能问题、安全隐患等代码问题。
14
五、回归测试
软 件 测 试
使用Jtest执行回归测试: 执行“Maintainable Regression Test Suite” 命令,生成回归测试套件。 修改源码后执行“Run Regression Tests”命 令。 如果该功能性改变是无意的,修改相应代码。 如果该功能性改变是有意的(如需求改变), 则用户可更改期望值,Jtest会在后续的测试中 按照更改后的预期输出,来进行相关的测试。
java单元测试使用方法
java单元测试使用方法Java单元测试是软件开发过程中非常重要的一环,它可以帮助我们确保代码的正确性和可靠性。
JUnit是Java中最常用的单元测试框架,以下是如何使用JUnit进行单元测试的简单指南:1. 添加JUnit依赖如果你使用Maven,你可以在你的``文件中添加以下依赖:```xml<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version></version><scope>test</scope></dependency>```如果你使用Gradle,你可以在你的``文件中添加以下依赖:```groovytestImplementation 'junit:junit:'```2. 编写测试类创建一个与你要测试的类同名的测试类,并添加`Test`注解。
例如,如果你有一个名为`Calculator`的类,你应该创建一个名为`CalculatorTest`的测试类。
3. 编写测试方法在测试类中,为每个要测试的方法添加一个测试方法。
测试方法应该以`test`开头,例如:`testAdd()`。
在测试方法中,你可以使用JUnit提供的断言方法来验证方法的输出是否符合预期。
例如,你可以使用`assertEquals()`方法来检查两个值是否相等。
4. 运行测试在IDE中,通常有一个运行所有测试或单个测试的选项。
你也可以使用Maven或Gradle在命令行中运行测试。
例如,对于Maven,你可以运行`mvn test`命令。
对于Gradle,你可以运行`gradle test`命令。
5. 分析测试结果测试结果通常会显示在控制台上,包括每个测试的执行情况以及任何失败的测试。
软件单元测试工具有哪些功能
软件单元测试工具有哪些功能单元测试在软件开发中扮演着至关重要的角色,它可以帮助开发人员快速准确地检测代码,降低错误率,提高代码质量。
为了提高单元测试效率,开发人员通常会选择使用专门的软件单元测试工具。
下面将介绍一些常见的软件单元测试工具及其功能。
1. JUnitJUnit是Java语言的一个单元测试框架,它提供了一组注解和断言方法,可以帮助开发人员编写和执行单元测试。
JUnit支持各种测试运行器和扩展,可以轻松地与其他工具集成。
功能包括断言方法、测试运行器、测试套件、参数化测试等。
2. NUnitNUnit是.NET平台下的一个单元测试框架,它提供了类似JUnit的功能,可以帮助.NET开发人员编写和执行单元测试。
NUnit支持多种测试运行器和扩展,可以进行参数化测试、并行测试、数据驱动测试等。
3. PHPUnitPHPUnit是PHP语言的一个单元测试框架,它可以帮助PHP开发人员编写和运行单元测试。
PHPUnit提供了各种断言方法、数据提供器、测试运行器等功能,支持代码覆盖率检测、依赖注入等特性。
4. JasmineJasmine是一个专门针对JavaScript的行为驱动开发(BDD)框架,它可以用于编写前端代码的单元测试。
Jasmine提供了描述性的语法风格,支持异步测试、Spy测试和模拟器等功能。
5. PyTestPyTest是Python语言的一个简单实用的单元测试框架,它易于学习和使用,并且支持灵活的参数化测试、测试夹具、模块化测试等功能。
PyTest还可以与其他Python测试工具集成,方便开发人员进行代码覆盖率检测和性能测试。
结论软件单元测试工具的功能多种多样,每种工具都有其独特的特点和优势。
选择适合自己项目的工具,并熟练掌握其功能和用法,可以帮助开发人员更快速地进行单元测试,提高代码质量,减少错误。
希望本文介绍的软件单元测试工具及其功能对您有所帮助。
软件单元测试工具有哪些
软件单元测试工具有哪些在软件开发过程中,单元测试是一个非常重要的环节,可以帮助开发人员验证代码的正确性并提前发现潜在的问题。
而为了更有效地进行单元测试,开发者通常会借助一些专门的软件单元测试工具。
下面将介绍一些常用的软件单元测试工具:JUnitJUnit是一个Java编程语言的单元测试框架,被广泛用于测试Java程序。
它提供了一套简单且易于使用的测试框架,可以帮助开发人员编写和运行单元测试。
JUnit在测试过程中可以断言代码中的预期行为与实际行为是否一致,从而验证代码的正确性。
PHPUnitPHPUnit是一个专门用于测试PHP程序的单元测试工具。
它支持很多测试类型,包括单元测试、集成测试和功能测试等。
开发者可以利用PHPUnit编写针对PHP代码的各种测试用例,验证代码的功能和性能。
SeleniumSelenium是一个自动化测试工具,主要用于Web应用程序的功能测试。
开发人员可以使用Selenium模拟用户在浏览器中的操作,如点击、输入文本等,来检查Web应用程序的各项功能是否正常工作。
Selenium支持多种语言,包括Java、Python、Ruby等。
PyUnitPyUnit是Python语言的一个单元测试框架,灵感来自于JUnit。
开发者可以利用PyUnit编写Python程序的单元测试用例,对Python代码进行全面的测试。
PyUnit提供了丰富的断言方法和测试运行器,可以帮助开发人员快速编写和运行测试。
JasmineJasmine是一个专门用于JavaScript代码测试的单元测试框架,支持BDD(行为驱动开发)风格的测试。
开发者可以使用Jasmine编写JavaScript程序的各种测试用例,验证代码的正确性和性能。
Jasmine的语法简洁清晰,易于上手。
MochaMocha是另一个流行的JavaScript测试框架,可以用于编写各种类型的测试,包括单元测试和集成测试等。
Mocha支持异步测试和并行测试,适用于大型项目的测试场景,能够帮助开发人员高效地进行测试工作。
Java 十大单元测试和自动化集成测试工具
Java 程序员需要用到十大单元测试和自动化集成测试工具一个优秀的程序员,必然能够很好地利用手头上的工具,因此我总在业余时间学习和探索新的工具和库,以下列表是我部分研究成果。
在这篇文章中,将分享10 个最为优秀且必不可少的工具,框架和库,这些可以帮助java 程序员在各类java 项目中编写单元测试和集成测试。
JUnitJUnit 无须赘述,即便是初级Java程序员,可能也已经听说过它,你可以使用它编写Java 代码的单元测试。
几乎所有主流IDE,例如Eclipse,NetBeans 和IntelliJ,都集成了JUnit,可以直接在这些IDE中编写和运行单元测试。
大多数人仍在使用JUnit 4,即使JUnit 5 已经发布,它很可能是今年下一个热点。
通过JUnit 5,可以将JUnit 同时应用于单元测试和集成测试,并且它还支持Java 8 的特性。
REST Assured用Java 语言测试和验证REST 服务,要难于Groovy 这类动态语言。
REST Assured 将这类语言的易用性带入了Java 领域,是一个优秀的REST API 的集成测试工具。
SeleniumSelenium 很可能是最流行的Java UI 测试工具了,它可以让你在不必启动浏览器的情况下测试JSP 页面。
你可以使用JUnit 和Selenium 来测试Web 程序的界面,它甚至允许你编写Web 应用程序的验收测试。
TestNGTestNG 是一个测试框架,其灵感来自JUnit 和NUnit,但同时引入了一些新的功能,使其功能更强大,使用更方便。
例如可以使用注解,在任意大的线程池中,配置各种可用策略进行测试(例如所有方法都在自己的线程中,每一个测试类使用一个线程等)。
因为TestNG 使用JUnit 4 的注解,同时又集成了HAMCSTREST 匹配器,它与JUnit 的差异已经减小了,但两者如何选择,这取决于你。
单元测试的工具有哪些
单元测试的工具有哪些单元测试是软件开发过程中非常重要的一环,它可以帮助开发者检验代码的可靠性、准确性和稳定性。
为了有效地进行单元测试,开发者通常会借助各种工具来简化和优化测试过程。
下面列举了一些常用的单元测试工具:JUnitJUnit是Java开发领域最流行的单元测试框架之一,它提供了一个简单而又强大的框架来编写和运行单元测试。
开发者可以使用JUnit编写测试用例,并通过断言来验证测试结果。
NUnitNUnit是.NET平台下的一种单元测试框架,它具有和JUnit类似的功能和语法。
NUnit支持各种测试类型,包括单元测试、参数化测试等,并提供了丰富的断言库来验证测试结果。
PytestPytest是Python语言下一种简单而又灵活的单元测试框架,它可以方便地编写测试用例并运行测试。
Pytest支持各种测试样式,包括函数式测试、参数化测试等,并提供了丰富的插件来扩展其功能。
MochaMocha是JavaScript领域下的一种流行的单元测试框架,它可以用于测试Node.js应用程序和浏览器端的JavaScript代码。
Mocha支持异步测试、并发测试等特性,并提供了丰富的断言库和插件生态系统。
XCTestXCTest是苹果平台下的官方单元测试框架,它可以用于测试iOS和Mac应用程序的代码。
XCTest提供了丰富的功能和API来编写和运行测试用例,并能够和Xcode无缝集成。
MockitoMockito是一个用于Java开发的Mock框架,它可以帮助开发者创建和管理模拟对象,从而简化对外部依赖的测试。
Mockito支持各种模拟操作,包括创建模拟对象、定义模拟对象的行为等。
上述列举的单元测试工具只是其中的一部分,开发者在选择测试工具时应根据自身的需求和项目特点进行选择。
通过合适的单元测试工具,开发者可以更加高效地进行代码测试和质量保证,从而提高软件的稳定性和可靠性。
软件开发中的软件测试自动化工具考核试卷
B. TestComplete
C. JMeter
D. LoadRunner
12.在自动化测试中,以下哪个概念表示对软件整体功能的测试?()
A.单元测试
B.集成测试
C.系统测试
D.回归测试
13.以下哪个工具主要用于API自动化测试?()
A. Postman
B. JMeter
C. Robot Framework
A. Cucumber
B. JBehave
C. TestNG
D. JUnit
13.以下哪些工具可以集成到持续集成/持续部署(CI/CD)流程中?()
A. Jenkins
B. Git
C. Maven
D. Docker
14.以下哪些工具提供了丰富的测试报告功能?()
A. TestNG
B. JUnit
C. Selenium
3. BDD是一种以行为为中心的开发方法,强调业务价值和然语言描述,开发团队参与更多。
4.选择因素:项目需求、测试类型、团队技能、工具成本和维护性。例:对于Web应用,可能选择Selenium;对于移动应用,可能选择Appium。
A. Selenium
B. TestComplete
C. QTP
D. Appium
17.在自动化测试中,以下哪个工具主要用于持续集成?(")
A. Jenkins
B. Git
C. Maven
D. Docker
18.以下哪个工具主要用于iOS移动应用自动化测试?()
A. Selenium
B. Appium
A. Selenium
B. Appium
C. JMeter
使用JUnit进行Java单元测试和Jenkins集成
使用JUnit进行Java单元测试和Jenkins集成Java作为一种非常常见的程序编程语言,在企业级应用程序中应用广泛,具有非常出色的可扩展性、稳定性和可靠性。
它的发展历程也非常漫长,从最早的Java SE到如今的Java EE,凭借着不断完善和创新,Java一直在技术领域占据着重要的地位。
虽然Java已经有了一些标准和规范,但是开发人员仍然需要进行一些测试,以确保其代码质量符合用户要求。
而JUnit是一个非常流行的Java测试框架,可以帮助开发人员快速准确地进行测试。
首先,我们来了解一下JUnit。
JUnit最早由Erich Gamma和Kent Beck共同创建,在开放源代码社区广泛使用,现在已成为Java领域中最流行的单元测试框架之一。
JUnit提供了一系列的API,可以帮助开发人员快速编写Java测试类、测试方法以及测试集。
开发人员只需要编写测试类和测试方法,JUnit将自动运行这些测试,并且在控制台上报告结果。
在JUnit中,测试方法应该具有@Test注解,以表明这是一个测试方法。
测试方法将接受任何参数和返回值类型,并且可以使用依赖注入和其他Java技术。
在测试方法内,可以使用断言语句来验证测试结果是否正确。
下面,我们来看一个JUnit测试类的例子:```javaimport org.junit.Test;import static org.junit.Assert.*;public class CalculatorTest {@Testpublic void testAdd() {Calculator calculator = new Calculator();int result = calculator.add(2, 3);assertEquals(5, result);}}```在上面的示例中,我们编写了一个CalculatorTest类来测试Calculator类的add方法。
java自动化测试框架以及实现方法
java自动化测试框架以及实现方法Java自动化测试框架以及实现方法为了保证软件质量和提升开发效率,自动化测试在软件开发过程中扮演着重要的角色。
Java作为一门流行的编程语言,也有许多成熟的自动化测试框架可供选择。
本文将介绍几个常用的Java自动化测试框架,并详细解释每个框架的实现方法。
一、JUnitJUnit是Java最流行的单元测试框架之一,被广泛应用于各种Java项目中。
JUnit通过提供一组注解和断言方法来简化单元测试的编写与执行。
以下是实现JUnit自动化测试的步骤:1. 导入JUnit框架:在Java开发工具中,导入JUnit的库文件,一般是一个jar包。
2. 创建测试类:创建一个新的Java类文件,用于编写测试代码。
3. 添加测试方法:在测试类中,使用@Test注解标记需要进行测试的方法。
4. 编写断言:在测试方法中使用JUnit提供的断言方法,对测试结果进行判断。
5. 运行测试:执行JUnit测试,查看测试结果。
JUnit提供了丰富的断言方法,如assertEquals(判断两个值是否相等)、assertFalse(判断条件是否为假)等,通过这些方法可以方便地进行单元测试。
二、TestNGTestNG是另一个流行的Java自动化测试框架,相比JUnit,TestNG提供了更多的灵活性和功能。
以下是实现TestNG自动化测试的步骤:1. 导入TestNG框架:将TestNG的库文件添加到项目中,例如通过Maven添加依赖。
2. 创建测试类:创建一个新的Java类文件,用于编写测试代码。
3. 添加测试方法:在测试类中,使用@Test注解标记需要进行测试的方法,可以添加多个测试方法。
4. 配置测试套件:使用TestNG的XML配置文件,配置测试类和测试方法。
5. 运行测试:通过指定配置文件,执行TestNG测试,并查看测试结果。
与JUnit相比,TestNG提供了更多的注解和配置选项,可以对测试进行更精细的控制。
使用JUnit Jupiter进行Java单元测试的新特性和实现方式
使用JUnit Jupiter进行Java单元测试的新特性和实现方式在软件开发过程中,单元测试是不可或缺的一环。
它可以帮助开发人员在代码编写过程中及时发现和修复潜在的问题,提高代码质量和可靠性。
而JUnit Jupiter 作为Java中最常用的单元测试框架之一,为开发人员提供了一系列新的特性和实现方式,使得单元测试更加简洁、灵活和易于维护。
一、JUnit Jupiter的新特性1. 注解模型JUnit Jupiter引入了一种新的注解模型,使得编写测试用例更加灵活。
与传统的@Test注解不同,JUnit Jupiter提供了一系列的注解,如@DisplayName、@Nested、@RepeatedTest等,可以根据需要对测试用例进行更加精细的控制和组织。
@DisplayName注解可以为测试用例指定一个更加友好和描述性的名称,方便开发人员理解和识别。
@Nested注解可以将测试用例进行分组,使得测试用例的结构更加清晰和易于管理。
@RepeatedTest注解可以指定一个测试用例被重复执行的次数,方便进行性能和稳定性测试。
2. 断言模型JUnit Jupiter提供了一套更加强大和丰富的断言模型,使得编写断言更加简洁和可读。
传统的断言方式通常使用JUnit的assertEquals、assertTrue等方法,而JUnit Jupiter引入了一系列新的断言方法,如assertAll、assertThrows、assertTimeout等。
assertAll方法可以同时执行多个断言,如果其中一个断言失败,会将所有失败的断言结果一起报告,方便开发人员查看。
assertThrows方法可以验证代码是否抛出了指定的异常,方便进行异常处理的单元测试。
assertTimeout方法可以限制代码执行的时间,方便进行性能和并发测试。
3. 扩展模型JUnit Jupiter引入了扩展模型,使得开发人员可以自定义扩展来满足特定的测试需求。
java单元测试自动生成原理
java单元测试自动生成原理
Java单元测试自动生成的原理是通过使用一些自动化工具和框架来帮助开发人员自动生成测试代码。
下面是一个常见的Java单元测试自动生成的流程:
1. 静态分析:通过使用静态代码分析工具,如FindBugs、PMD等,检查源代码中的可能的错误和问题。
2. 代码覆盖率分析:使用代码覆盖工具,如JaCoCo等,分析源代码覆盖率,找到未被覆盖的代码片段。
3. Mock对象生成:使用Mock框架,如Mockito、EasyMock等,生成模拟对象以模拟真实环境中的依赖对象。
4. 测试用例生成:根据源代码和静态分析结果,使用符号执行、模糊测试等技术来生成测试用例。
5. 测试代码生成:根据生成的测试用例和模拟对象,自动生成相应的测试代码。
6. 测试执行和结果分析:执行生成的测试代码,收集执行结果和覆盖率信息,分析测试结果,生成报告。
这些自动化工具和框架能够帮助开发人员自动生成具有良好覆盖率的测试代码,并提供有效的测试策略和测试报告,从而提高软件质量和开发效率。
代码自动化测试工具使用技巧
代码自动化测试工具使用技巧章节一:介绍自动化测试工具自动化测试是现代软件开发过程中必不可少的一环。
为了提高测试效率和质量,开发人员需要借助自动化测试工具来执行各种测试任务。
自动化测试工具可以帮助开发人员快速运行测试用例,检测代码错误和缺陷,并提供详细的测试报告。
本章将介绍几种常用的自动化测试工具。
1.1 单元测试工具单元测试是对代码最小可测试代码单元进行测试的过程。
常见的单元测试工具有JUnit(Java)和NUnit(.NET),可以自动运行测试用例并生成测试报告。
这些工具可以帮助开发人员捕获代码错误、缺陷和性能问题,并及时进行修复。
1.2 集成测试工具集成测试是测试多个模块或组件之间的接口和交互的过程。
常见的集成测试工具有Selenium和Cucumber(支持多种编程语言),它们可以模拟用户操作并对Web应用程序进行自动化测试。
这些工具可帮助开发人员验证代码是否正确地集成,并确保整个系统的功能正常运行。
1.3 接口测试工具接口测试是测试系统与外部组件或服务之间接口的过程。
常见的接口测试工具有Postman和SoapUI,它们可以帮助开发人员自动发送请求并验证响应。
这些工具能够检测接口是否遵循规范,并测试系统的性能和可靠性。
1.4 性能测试工具性能测试是测试系统在负载条件下的性能、稳定性和可靠性的过程。
常见的性能测试工具有JMeter和LoadRunner,它们可以模拟多个用户同时对系统进行访问,并提供详细的性能指标和报告。
这些工具能够帮助开发人员发现系统的性能瓶颈,并进行优化和调整。
章节二:代码自动化测试工具的使用技巧2.1 选择适合的自动化测试工具在选择自动化测试工具时,需要考虑测试的需求、技术栈和团队能力。
如果需要对Java开发的Web应用程序进行测试,可以选择使用Selenium进行自动化测试。
如果需要对接口进行测试,可以选择使用Postman或SoapUI。
选择适合的工具将能够提高测试效率和准确性。
单元测试的常用工具
单元测试的常用工具在软件开发过程中,单元测试是保证代码质量和功能稳定性的重要环节。
为了有效进行单元测试,开发人员通常会借助各种工具来简化测试的过程,提高测试的覆盖率和准确性。
本文将介绍几种常用的单元测试工具,帮助开发人员更好地进行单元测试。
1. JUnitJUnit 是 Java 测试框架中最流行和广泛使用的工具之一。
它支持编写简单、易于理解的单元测试代码,并提供丰富的断言库来验证代码的正确性。
开发人员可以通过 JUnit 运行重复性的测试用例,快速发现代码中的问题,并及时进行修复。
2. NUnitNUnit 是一个针对 .NET 平台的单元测试框架,与 JUnit 类似,它提供了丰富的断言库和易于编写的测试代码结构。
NUnit 支持并行测试执行和参数化测试,帮助开发人员更高效地进行单元测试,并能够集成到持续集成环境中。
3. PHPUnitPHPUnit 是针对 PHP 语言的一个流行的单元测试框架,具有丰富的功能和灵活的配置选项。
开发人员可以通过 PHPUnit 编写测试用例、执行测试代码,并生成详细的测试报告。
PHPUnit 还支持测试覆盖率的统计和代码重构功能,帮助开发人员提高代码质量。
4. MochaMocha 是一个用于 Node.js 和浏览器的 JavaScript 测试框架,支持异步测试、链式调用和丰富的断言库。
开发人员可以通过 Mocha 编写清晰结构的测试代码,并通过各种插件和扩展来扩展框架的功能。
Mocha 还支持针对前端页面的端到端测试,帮助开发人员全面测试应用程序的功能和性能。
5. JestJest 是一个由 Facebook 开发的 JavaScript 测试框架,专注于简化测试的配置和执行过程。
它集成了多种功能,包括断言库、覆盖率检测、快照测试和模拟测试等,帮助开发人员编写高效、可靠的测试代码。
Jest 还提供了友好的命令行界面和详细的测试报告,使测试过程更加便捷和可视化。
Java自动化测试工具有哪些值得一试
Java自动化测试工具有哪些值得一试在当今的软件开发领域,自动化测试已经成为了确保软件质量和提高开发效率的关键环节。
对于使用 Java 进行开发的项目来说,选择合适的自动化测试工具至关重要。
接下来,让我们一起探索一些值得一试的 Java 自动化测试工具。
首先要提到的是 JUnit。
这是 Java 领域中最为广泛使用的单元测试框架之一。
它提供了简洁明了的 API,使得编写和运行单元测试变得轻松简单。
通过使用断言方法,我们可以方便地验证测试结果是否符合预期。
而且,JUnit 还支持各种扩展,例如参数化测试、规则等,能够满足不同复杂程度的测试需求。
TestNG 也是一款出色的测试框架。
与 JUnit 相比,TestNG 提供了更强大的功能和更灵活的配置选项。
它支持依赖测试方法、分组测试、多线程执行等特性。
这使得在处理大规模的测试套件时,TestNG 能够更有效地组织和执行测试用例,提高测试效率。
Selenium 则是用于 Web 应用程序自动化测试的首选工具之一。
它支持多种编程语言,包括 Java。
通过 Selenium,我们可以模拟用户在浏览器中的操作,如点击、输入、页面导航等。
结合各种浏览器驱动,Selenium 能够在不同的浏览器上进行测试,确保 Web 应用在各种环境下的正常运行。
JMeter 主要用于性能测试。
如果您需要对 Java 应用的性能进行评估和分析,JMeter 是一个不错的选择。
它可以模拟并发用户访问,收集性能指标,如响应时间、吞吐量等,并生成详细的测试报告,帮助我们发现潜在的性能瓶颈。
Cucumber 是一种行为驱动开发(BDD)框架。
它使用自然语言来描述测试场景,使得非技术人员也能够理解和参与到测试过程中。
对于需要跨团队协作和沟通的项目,Cucumber 能够促进开发人员、测试人员和业务人员之间的有效交流。
Mockito 是一个流行的模拟框架。
在单元测试中,当某些依赖对象难以创建或者其行为不可预测时,我们可以使用 Mockito 来创建模拟对象,并控制它们的行为,以便更专注于测试目标代码的逻辑。
单元测试案例生成 工具
单元测试案例生成工具
有许多工具可以帮助生成单元测试案例,一些流行的工具包括:
1. JUnit:JUnit是Java语言中最流行的单元测试框架之一。
它
提供了一些注解和断言方法,可以帮助开发人员编写测试用例并运行它们。
2. Mockito:Mockito是一个用于Java的Mock框架。
它允许开发人员创建模拟对象,并定义它们的行为,以支持单元测试的编写。
3. PyTest:PyTest是Python语言的一个优秀的单元测试框架。
它提供了一些强大的功能,如自动发现测试用例、参数化测试和丰富的断言方法。
4. Selenium:Selenium是一个用于自动化浏览器测试的工具。
它可以模拟用户在浏览器中的操作,并验证网页的正确性和功能。
5. Postman:Postman是一个API开发和测试的工具。
它允许
开发人员发送HTTP请求,并验证响应的正确性。
这些工具都能够帮助开发人员自动生成单元测试案例,提高测试的覆盖率和质量。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
JUTA:一个Java自动化单元测试工具严俊1郭涛2阮辉1玄跻峰31(中国科学院软件研究所北京100190)2(中国信息安全测评中心北京100085)3(大连理工大学数学科学学院辽宁大连116024)(junyan@)JUTA:An Automated Unit Testing Framework for JavaYan Jun1,Guo Tao2,Ruan Hui1,and Xuan Jifeng31(Institute ofSoftware,Chinese Academy ofSciences,Beijing100190)2(China Information Technology Security Evaluation Center,Beijing100085)3(Schoolof Mathematical Sciences,Dalian University of Technology,Dalian,Liaoning116024) Abstract Testing is very important and time consuming in the development of high-quality softwaresystems.This paper proposes an automatic testing tool JUTA for unit testing of Java programs.The approach is based on sharp analysis of the programs.JUTA firstly employs the Java optimization framework Soot to parse a single Java method into byte code and translates it into a control flow graph(CFG).It then performs depth-first or breadth-first search on the CFG to extract paths from it.Sometechniques such as path length restriction are used to prevent path number explosion.Finally JUTA analyzes the paths based on the combination of symbolic execution and constraint solving.The goal ofpath analysis lies in two folds.It can generate a set of test cases satisfying the test criterion such as statement coverage.The test set typically has small number of test cases that are all executable.In addition to test generation for dynamic testing,it can also be used in static testing.JUTA can reveal certain kinds of errors from the source code automatically if the user provides proper assertions to describe the errors.The experimental results show that this tool is efficient for both dynamic andstatic testing.Key words Java unit testing;dynamic testing;static testing;program analysis;symbolic execution 摘要描述了一个Java自动化的单元测试工具JUTA.JUTA首先调用工具Soot解析单个Java方法的源码,并将源码解析成一个控制流图.在此基础上,采用符号执行的方法分析控制流图上的路径.工具能够自动地产生满足覆盖率标准的程序的测试用例.这种方法产生的所有测试用例都是可执行的,并且一般来说具有较小的测试用例数.如果用户能够合理地给出描述程序错误的断言,框架JUTA 能够自动地检查源码中部分特定类型的错误.实验结果表明工具对Java单元代码的动态测试和静态测试均能在可接受的时间内给出有效的结果.关键词Java单元测试;动态测试;静态测试;程序分析;符号执行中图法分类号TP3110引言软件质量历来就是学术界和工业界共同关心的问题,因为软件质量问题造成巨大经济损失事件不胜枚举.当前,随着信息技术的迅速发展,特别是互联网技术的广泛应用,Java技术以其通用性、平台移植性、安全性等特征,吸引了众多软件开发者,在各个重要的行业部门得到了广泛的应用.因此,如何提高软件质量,尤其是提高应用广泛的Java程序的可靠性,长期以来一直是一个非常重要的研究课题.软件测试是提高软件质量的重要手段.优秀的软件开发机构把40%的工作量花在软件测试上,软件测试费用则占到了软件开发总费用的30%~50%,而对于一些要求高可靠性、高安全性的软件,测试费用已经抬高到了整个软件项目开发所需费用的3~5倍.单元测试是软件测试的早期阶段,这种测试方法主要测试程序的单元函数或者类中的方法,其主要原理是对源代码中的控制结构和处理过程等进行分析,检查程序内部处理是否正确,包括语句结构、分支和循环结构等.由于单元测试需要分析源代码,所以测试的代价往往比较高.目前,在工业界,单元测试大多仍然是靠人工完成的,如手工设计测试用例、人工审阅代码等,不但十分繁琐,而且测试质量与测试人员的主观经验紧密相关.随着计算机软硬件规模的不断发展,以人工为主的测试方法已经无法满足测试的需求.目前,采用计算机辅助的自动化软件测试技术成为软件工程中一个活跃的研究领域.本文介绍一个Java自动化的单元测试工具JUTA(an unit testing and analyzing tool for Java).与Junit等传统测试框架不同,JUTA提供了一系列的精度和自动化程度较高的技术来生成测试用例以及检查代码中的错误,以提高测试的自动化程度和效率.1预备知识本节将简要介绍JUTA采用的控制流和数据流分析技术.1.1控制流图形式化地说,控制流图(control flow graph,CFG)是一个有向图G= N,E,s,f ,其中N代表节点的集合,E代表边的集合,s和f分别表示控制流图的起点和终点.图中每个点n∈N代表程序中的一系列顺序运算(即这些语句在程序执行过程中要么全部都执行,要么全部都不执行),或者说是一个基本块(basic block);而每条边,e=(ni,nj)∈E,代表从节点ni到nj的一个转移.用流图作为程序结构的模型时,程序的运行过程可以用流图中的路径来刻画.控制流图中的一条执行路径p代表一个执行序列p= n1,n2,…,nm ,其中m是路径的长度, (ni,ni+1)∈E(1≤i<m).一般来说,程序的执行必须从起点s开始.我们称n1=s的这条路径为部分路径(partial path).如果n1=s并且nm=f,我们称p是程序的一条完整路径(complete path).在下文中,如无特殊说明,我们所说的程序路径都是完整路径.例1.图1为一段简单的代码及其控制流图.函数foo根据输入i和j的值计算参数good的值并返回.从控制流图上易知程序有3条从起点S到终点F的完整路径:p1= S,S1,S2,S3,S4,F ,p2=S,S1,S2,S3,F ,p3= S,S1,F .public intfoo(inti,intj){*S*intgood=TRUE;*S1*if((i>2)&&(j>3)){*S2*j-- ;*S3*if(i+2*j<5)*S4*good=FALSE;}*F*returngood;}Fig.1 A piece of example code.图1一段示例代码对于基于控制流图的结构测试来说,主要的测试方法就是找到一系列的可行测试路径,这些路径的输入数据就是测试用例.例如在例1中,{i=3,j=4}就是对应于路径p2的一个测试用例.测试人员通过执行这些测试用例来检查程序的错误.显然, 由于程序代码的复杂性,通过枚举所有的测试路径来测试程序是不现实的.为了减少测试的代价,人们定义了一系列的测试覆盖准则(coverage criterion), 作为测试的标准来限制测试集的大小[1].最简单的控制流覆盖准是语句覆盖(statement coverage,即在软件测试过程中,只有当程序中的所有语句都得到了运行,才能称该测试是充分的)和分支覆盖(branch coverage,即要求在软件测试过程中,所有1841严俊等:JUTA:一个Java自动化单元测试工具的控制转移都得到了覆盖).由于在控制流图模型中,语句与节点相对应,语句覆盖意味着测试路径覆盖所有的节点.同样地,分支覆盖就是所有的测试路径覆盖了控制流图中所有的边.1.2基于路径的程序测试程序中的一次完整的执行过程对应控制流图中的一条完整路径.但是,并不是所有的完整路径都代表程序中的一次运行过程.这是因为可能不存在输入数据使得程序按照该路径执行.这样的完整路径称为不可行路径(infeasible path),否则称为可行的(feasible)[2].例如,在例1中,路径p1执行的语句如图2所示(符号“@”后的表达式表示程序执行该逻辑判断为真的分支).易知,程序执行到第2个判断语句时,表达式(i+2×j<5)不可能满足,程序控制流图中的分支S3-S4不可能被执行到.那么,路径p1是一条不可行的路径.good=TRUE;@((i>2)&&(j>3));j=j-1;@(i+2×j<5);good=FALSE;Fig.2Pathp1.图2路径p1由于控制流测试准则都是基于控制流图中的测试路径来定义,很自然地,我们可以采用如下方法来生成测试用例:首先从控制流图中找到一组路径满足覆盖准则,然后从每条路径中找出各变量的一组初始值使得程序能够按照路径执行,这些初值就构成了测试用例集合.一般来说,一个自动测试用例生成(automated test case generation)系统主要可以分成3个部分[3]:1.程序分析器(program analyzer),其主要工作是把程序转化成容易处理的中间模型(一般就是我们前面提到过的控制流图);2.路径选择器(path selector),如何选择路径满足我们的测试需求(比如覆盖准则);3.测试数据生成器(test data generator),如何从测试路径中得到我们需要的测试数据.在实际开发中,程序分析器也被称为前端(frontend),后两部分合起来被称为后端(backend).这样的自动测试生成的系统主要用于程序的动态测试,即采用测试用例测试被测程序.与动态测试对应的静态测试方法,其框架与测试生成大体相同.主要的不同指出在于其输出并不是测试用例,而是直接报告程序是否包含某类错误,或者给出能检出某类错误的具体的测试数据.由于程序测试的需求众多,实际的测试系统尤其是商用系统,可能还包括一些其他的辅助模块,比如测试脚本的自动生成器等.1.3路径分析方法不可行路径给自动化测试带来了一个难题,我们不可能简单地通过从程序控制流图的信息中抽取路径来选择测试用例,在测试用例选择时必须分析数据流的信息.为了精确地分析控制流图中一条完整的路径,我们可以采用符号执行(symbolic execution)[4] 的方法.所谓符号执行,相对于普通的程序执行来说,就是程序并不真正用数值来替换程序的变量,而是用一组关于初始值的表达是来表示程序中出现的项.用符号执行加约束求解进行程序分析的基本思想是:采用Hoare逻辑可以将程序路径表示成{P}Q{R},其中P是程序的前置条件(pre-condition.执行程序前需要满足的条件,或者称为前断言),R是程序的后置条件(post-condition,程序执行后需要满足的条件,或者称为后断言).假定在程序的符号执行过程中由{P}Q可以推导出约束条件c1∧c2∧…∧cn,则应该有c1∧c2∧…∧cn※R.在一般的测试中,如果后断言永真,那么可以对约束条件c1∧c2∧…∧cn求解,可以得到变量的初值,从而得到测试用例.另一方面,我们可以对约束c1∧c2∧…∧cn∧瓙R求解,如果有一组解满足这一约束,说明存在一组输入使运行程序的结果和规范不符.如果程序的规范正确,则程序中必定包含错误.对于不包含函数调用代码来说,程序的语句可以分成3类:1)动作(action),也就是赋值语句;2)判断语句(predicate),也就是一个逻辑表达式;3)其他不影响变量的表达式,如控制台打印语句System.out.println.我们用一个具体的例子说明符号执行的原理.考虑图2的路径p1,如果i和j的初值为i0和j0,我们可以自顶向下依次执行这段程序,用程序的赋值语句替换判断语句,最后得到一个只含有判断语句的约束集合{i0+2×(j0-1)<5;(i0>2)&&(j0>3)}.这个集合就是程序初值的约束.由于这个约束集是不可满足的,所以路径p1 是不可行的.关于符号执行的具体细节请参考文献[2,5-6].符号执行的好处是能够精确地分析程序的行为,但它的缺点也是显而易见的.由于符号执行方法过于依赖源代码,并且需要消耗较大的计算资源,因而无法精确分析带有很多模块调用(特别是当这些子模块代码不可见的时候)的程序.同时,程序需要能够用约束精确模拟复杂程序结构,比如指针和数组的执行,这是一件很困难的事情.最后,为了保证分析的精确性,符号执行需要有一个能力非常强的完备解法器(complete solver,就是说,只要约束有解,解法器必然能够给出一组解).针对不同的程序, 这个解法器可能需要处理位操作等复杂的约束.这一点也限制了符号执行方法的使用.工具JUTA中采用较为简单的方式在工具的处理能力和精确度之前作了一个平衡.我们将程序中的表达式限制为布尔逻辑和线性数值约束两种类型,并且将程序的外部调用抽象成简单的赋值语句和后置断言.具体内容见本文第2节.2工具JUTA的设计与实现本节将详细介绍JUTA工具的流程以及工具的模块组成,同时对每一个模块给出其功能以及简要的描述,主要目的是为工具提供一个整体的框架描述.2.1工具流程为了便于理解源程序需要对程序的源代码进行一定的处理.首先要做的就是编译分析,包括语法语义错误的检查、建立中间表示(intermediate representation,IR)并生成控制流图等.同时为了以后的分析,我们还需要识别出源代码中的循环,并对循环进行处理,建立一棵循环控制树.这部分通常成为前端处理.有了前端处理的程序结构和数据信息, 我们就可以通过算法遍历控制流图,得到一系列的路径,并通过符号执行和约束求解来分析这些路径, 对其可行性进行判断,对于可行的路径为其生成测试数据,最后收集这些测试数据就得到了满足某些性质的目标测试数据集.因而,从整体上工具分为两个部分:前端处理和后端分析,其整体结构如图3所示:Fig.3Framework of JUTA.图3JUTA的框架目前,工具JUTA实现了两方面的功能:静态测试与动态测试.本文1.2节曾指出,这两种测试方法可以公用相同的前端,主要区别在于工具的后端.接下来我们将按照功能分别介绍工具的各模块.2.2工具输入工具输入包含两部分.首先是被测的Java源码.源码中包含被测Java代码的单个方法.由于工具JUTA的主要功能是完成单元测试,所以,工具将丢弃方法中的外部调用.用户在测试时,需要手工将重要的外部调用替换成赋值语句或者约束表达式.例如,对于语句y=foo(x),假定外部调用foo将y的值改变为foo x,并且这个值的范围是[lb,ub].那么可以将这行代码替换为:y=foo x;assert(lb< =foo x&&foo x< =ub);另一部分的输入是一些描述性质的断言以及断言的插入位置.具体请参见本文2.4.2节.2.3前端处理前端分析整体上相当于一个编译器的前端,功能上相当于一个不产生目标代码的编译器.在这一部分我们借用的是Java分析优化工具框架Soot[7]的编译分析功能.Soot是一个功能很强大的分析框架,融合了编译前端以及分析器的各种功能.工具JUTA的前端在Soot框架下扩展其功能,产生后端分析所需要的中间结果.在JUTA中,我们主要使用了Soot的语法语义检查、中间表示、循环控制分析以及控制流图1843严俊等:JUTA:一个Java自动化单元测试工具生成等模块.接下来简要介绍这几个模块的功能.2.3.1语法语义检查模块该模块主要完成源代码语法语义的检查,确保给定的输入程序是没有语法语义错误的,同时建立一棵等价于源程序的抽象语法树.2.3.2中间代码生成模块这部分通过遍历抽象语法树,对各种语句进行处理,产生中间表示,便于以后的分析和处理.Soot提供了4种中间表示形式:Baf,Jimple,Shimple和Grimp.工具JUTA使用了Soot的Jimple中间表示.Jimple是一种简单的带类型的3地址表示形式.例如图4为Java源码与对应的Jimple代码.图4(a)所示的一段简单的Java代码,经过Soot翻译后得到图4(b)所示:public static intfunc(intx){inty= -1;if(x>0)y=1;elsey=2;returny;}public static intfunc(int){intx,y,temp$0,temp$1;x:= @parameter0:int;y= -1;ifx>0 goto label0;goto label1;label0:nop;temp$0=1;y=temp$0;goto label2;label1:nop;temp$1=2;y=temp$1;label2:nop;returny;}(a) (b)Fig.4Java source code and the corresponding Jimple code.(a)Java source and(b)Jimple code.图4Java源码与对应的Jimple代码.(a)Java源码;(b)Jimple代码2.3.3控制流图建立模块本模块通过遍历中间表示的列表,将中间表示序列划分为基本块,控制流图即是以基本块为节点的有向图,描述了源代码中的控制流.工具JUTA使用Soot中的Brief Block Graph,只为源代码中基本的控制流提供支持,目前无法处理异常(exception).2.3.4循环控制分析模块这一部分主要是分析控制流中的循环,Soot中将每一个循环抽象成一个对象,每一个循环都存储自己的循环头部以及循环体.一般来说,结构化的程序中的循环分成3类,孤立循环(single loop)、嵌套循环(nesting loop)以及串联的循环(concatenatedloop)[8].我们可以建立一个抽象的循环控制森林,森林中每一个节点是一个表示循环的对象,用来描述循环之间的关系.循环A是循环B的子节点,当且仅当循环B内嵌在循环A之中.当被测程序中不包含串联循环时,循环控制森林退化为循环控制树.2.4后端分析本节将介绍工具的后端.考虑到动静态测试的不同之处,我们将分别介绍动态和静态测试的功能模块,之后对两者进行一个比较.2.4.1动态测试后端动态测试的目标是生成一组满足覆盖率的测试数据.所以,动态测试的后端需要分析前端处理后得到的数据信息(包括中间表示、控制流图以及循环控制树),根据路径产生策略以及覆盖准则产生满足要求的路径,并且通过分析路径的可行性得到测试数据.这一部分有以下4个模块:路径生成、路径转换、路径分析以及路径选择.1)路径生成模块这一模块将分析由前端处理得到的控制流图,并抽取出一系列的路径.这些路径可以用基本块的编号序列表示.路径的产生过程是通过遍历控制流图来得到的.由于程序中可能有循环,那么,从图中可能抽取出无限条路径.为了产生有限条测试路径, 我们可以限制循环次数或者限制路径的长度(路径表示中基本块的个数).在工具JUTA中可以通过参数来选择使用的路径限制策略.路径产生是一个遍历控制流图各顶点的过程,在图的遍历算法中有两种常见的策略:深度优先遍历(DFS)和宽度优先遍历(BFS).当采用BFS算法时,是按照路径长度由短到长的次序生成路径,所以在队列中需要存储最多两层的中间节点,当路径长度限制比较大或者循环次数限制值比较大时,队列中需要存储很多的节点.在使用DFS算法时,由于优先考虑循环的退出节点,在栈中存储的元素数目比较少,但是生成的最终路径不是按照由短到长的顺序.而且很多路径都是由几个相同的基本块所组成.由上述的比较可知,使用DFS占用较少的系统资源,但是在处理过程中,尤其是在CFG包含环时容易陷入一个分支无法跳出,无法快速达到覆盖率指标, 比较适用于静态测试;使得BFS能够较快达到覆盖率,但是代价相对较高,适用于在测试覆盖准则指导下的测试生成.工具JUTA的路径生成模块实现了这两种策略,用户也可以用参数指定所使用的遍历策略.在默认情况下使用的是深度优先.2)路径转换模块前面1.3节中介绍过,对于不包含函数调用代码来说,程序的语句可以分成3类.而我们主要关注其中两类语句,即赋值和判断.路径转换模块将采用基本块的编号序列表示的路径,根据基本块对应的Jimple中间表示,翻译成一些简单的赋值和判断语句,方便下一步的路径分析.3)路径分析模块这一部分主要是用来对产生的路径进行分析.张健等人在文献[2,5-6]中提出了基于符号执行以及约束求解的路径分析方法,并给出了一个工具EPAT用于判断C程序路径的可行性.目前,EPA T支持布尔逻辑表达式和线性数值约束表达式及其混合,同时还支持数组和指针下标的运算.考虑到经过断言插入和路径转换后的路径只包含两类基本的表达式:判断和赋值,从而可以调用EPAT来分析Java程序的路径条件,判断出路径是否可行,并对可行的路径产生测试数据.4)路径选择模块为了采用较少的测试数据测试程序,可以在所有可行路径中选择一些有代表性的路径来测试被测代码.可行的选择标准就是覆盖准则,例如语句覆盖.在这种测试方法中,我们力图用最少的测试数据去覆盖尽可能多的语句或者是基本块.这个问题实际上是一个测试集约简(test reduction)问题.Wang等人指出,这种以覆盖路径中的点或者边为目标的测试约简问题可以采用线性规划方法求解[9].具体到这个问题,由于路径生成模块可能产生的路径数目太多,一般的线性规划工具无法处理这么大规模的问题,工具JUTA通过以下3个步骤来约简测试集.①不可行路径删除.首先要做的就是删掉不可行路径.这一步在我们的前几个模块已经完成,所以可以不用考虑.②删除冗余路径.采用贪心算法来减少可行路径集合的大小,将那些对覆盖率没有贡献的测试路径予以删除.③寻找最优路径集合.可以使用线性规划工具进一步删除冗余的路径,得到一个最小的路径集合. 实验结果表明,这个路径约简方法能够得到接近最优的测试集合(参见3.1节).2.4.2静态测试后端静态测试的目标是给出程序是否包含某类错误的一个判断.在原理上,工具JUTA的静态测试与动态测试都是采用路径分析方法,所以静态测试后端重用了动态测试后端的3个模块,即路径生成、路径转换、路径分析.在本文1.3节中指出,可以通过简单的断言来描述程序的错误性质,从而自动地、静态地检查程序的错误.为了便于用于描述程序错误性质,工具在静态测试的后端中的路径分析模块之前增加一个模块,用于在路径中插入断言表达式.当此模块功能打开时,工具JUTA的输出就是满足这些条件的测试路径集合.在工具JUTA中,断言插入模块读入条件表达式,并将这些条件插入到路径的相应位置.目前, JUTA支持在指定的基本块前后加入前置或者后置条件.断言的语法形式是BBID expr Position Mode,其中:①BBID表示基本块的编号;②expr表示描述错误的性质的条件表达式,目前支持线性数值约束与布尔逻辑约束的混合;③Position表示插入断言的位置有两个选项:pre和post,分别表示插入到基本块之前或者之后;④Mode表示断言插入的模式,有4种选项,F表示在路径中第1次出现该基本块时插入;L表示在路径中最后一次出现该基本块时插入,A表示在所有的基本块的对应位置插入该断言;而当这一项为一个数值i时,表示在该基本块第i次出现的位置插入断言.例2.假定为了测试如下循环程序是否有数组下标越界的错误.*block 14*for(inti=0;i<n;i++){*block 15*read(a[2*i]);}我们在基本块15中发现被测程序对数组a[]下标进行了运算,则可以在基本块15之后加入如下条件表达式(假定数组大小20),描述下标越界:15(2*i<0‖2*i> =20)post L,然后让工具枚举从控制流图起点到基本块15的部分路径并检查可行性.这样,如果JUTA输出一条可行的部分路径,即存在一条可以执行的输入使得描述错误的断言可满足,则表示程序在基本块15中可能含有数组下标越界的错误.1845严俊等:JUTA:一个Java自动化单元测试工具2.4.3动静态测试后端的不同之处动态测试需要分析完整路径并给出测试数据,而静态测试并不需要给出完整的路径,只需找到包含错误的部分路径即可.因而在静态测试中,路径生成模块给出的路径是以可能出错的基本块为终点的部分路径.另外,静态测试需要一个断言插入模块插入用户定义的断言以检查程序中的错误,而动态测试需要一个路径选择的模块来约简测试集.表1比较了两个后端的不同之处:Table 1Comparison Between the Backends of Static and Dynamic Testing表1静态测试与动态测试后端比较Module Static Testing Dynamic TestingPath Generation Partial Path Complete PathAssertion InsertionInsert User WrittenAssertions-Path Selection-Test set reduction3实例研究本文我们将通过部分实例来展示工具的功能.3.1动态测试动态测试的目标是产生测试用例,并达到测试覆盖率.我们选择了6个方法实例,设置每个循环限制的循环次数上限是3次,覆盖准则是语句覆盖,得到一个可行路径集合F.然后通过路径选择模块约简得到一个最优测试集合O.表2列出了实验结果,所有实例的运行时间均在1 min以内.这里,圈复杂度(cyclomatic complexity)[10]描述了程序的逻辑复杂度,其定义为v(G)=e-n+2=d+1,其中,e为控制流图中边的数目,n为节点(基本块)的数目,而d为控制流图中判断节点(conditionnode,假定程序中所有的判断节点均为二叉节点)的个数.一般来说,满足语句覆盖的最后测试集的大小不超过代码的圈复杂度[1].Table 2Unit Test Generation表2单元测试用例生成Functionv(G) F OtriDiv6 11 3reminder2 5 1bubbleSort4 33 2binarySearch3 5 1insertSort4 9 1。