专利名称:基于执行序列的JUnit测试用例化简方法
技术领域:
本发明属于软件测试中的测试用例化简技术领域,是一种针对Java程序的JUnit 测试用例化简方法。
背景技术:
软件测试是确保软件质量的重要手段。由于软件开发过程中程序员无法保证代码的正确性,因此,软件测试是软件开发阶段必不可少的重要过程。另一方面,软件测试代价 大,占整个软件开发和维护过程总开销的一半。JUnit是目前主流的针对Java程序的测试用例框架,当前程序开发人员多手工 或使用JTest,JCrasher, Randoop等工具自动生成JUnit形式的测试用例来测试Java程 序。虽然测试用例生成工具可以方便快捷地为程序开发人员随机地生成大量的测试用例, 但是,大量测试用例的执行会增大软件测试的时间开销和资源开销。而且,当软件测试的时 间或资源受限时,软件测试过程有时也无法执行所有这些大量的测试用例。为了有效地利 用现有的测试用例,在减少软件测试各种开销的同时保证软件测试的效果,需要对手工编 写或工具自动生成的测试用例构成的集合进行化简,这是本发明提出的动机之一。在软件开发过程中,为了确保修改后的程序的正确性,程序开发人员需要对修改 后的代码进行测试,这一过程称为回归测试。在回归测试过程中,程序员可以使用原程序的 JUnit测试用例来测试修改后的Java程序。但是,针对原程序的测试用例很多,为了减少回 归测试的开销,需要把针对原程序的JUnit测试用例进行化简,这是本发明提出的另一个 动机。目前已有的测试用例化简技术,主要是用于解决回归测试过程中的测试用例化简 问题,而不是一般的软件测试过程。这些技术主要根据测试用例在原程序执行过程中的结 构性覆盖(比如语句或分支覆盖)对测试用例进行化简,从而保证化简前后的测试用例集 合能够满足相同的结构性覆盖。这种基于测试用例执行信息的化简技术,无法解决一般软 件测试过程中的JUnit测试用例化简问题,因为后者没有办法提供JUnit测试用例的执行 fn息ο现有的Jupta技术是一种测试用例排序技术,它可以扩展用于测试用例化简,但 是这一技术与本发明要解决的问题不同。Jupta技术分析每条JUnit测试用例的静态调用 图,Jupta技术预知每条测试用例在执行过程中可能执行到的方法,以此为基础计算每条测 试用例的揭错能力,并对测试用例集合进行化简。使用Jupta技术,化简后的测试用例集合 的揭错能力要明显小于化简前。这是因为Jupta技术仅仅根据测试用例对单个方法的覆盖 来选择测试用例,可是程序中的某些故障不是源于单个方法本身的错误,而是多个(至少 两个)方法的调用顺序不当。Jupta技术选出的测试用例无法保证揭示这类故障,因此,使 用Jupta技术化简后的测试用例集合的揭错能力要小于原测试用例集合。
发明内容
本发明的目的是给出一种测试用例化简技术,针对JUnit形式的测试用例构成的 集合T进行化简,并使化简后的测试用例构成的集合T"能够满足下面几个条件(I)T"对方法调用顺序不当导致的故障的揭错能力与T相同;(2)T"的揭错能力与T的揭错能力接近;(3)Τ〃是T的真子集。本发明的技术方案如下JUnit测试用例是一组方法和类构成的可执行程序。本发明只关注每条JUnit测 试用例包含的方法以及它们之间的顺序关系,忽略程序中的其他语句。不同于已有的测试 用例化简方法,本发明在测试用例化简前后不仅关注源于单个方法本身的故障,也关注源 于方法调用顺序(比如push和pop之间顺序调用关系)不当引起的故障。本发明提出了 一种k-序列的表示方法来描述每条JUnit测试用例——体现了每条JUnit测试用例对方 法的调用顺序,并将所有JUnit测试用例包含的方法调用序列作为化简前后需要保持不变 的条件,对JUnit测试用例集合进行化简,从而保证化简前后的测试用例集合都可以揭示 源于单个方法调用不当和源于多个方法调用顺序不当的错误。简单来说,本发明包括两个步骤(1)使用k_序列的集合来表示JUnit测试用例集合中的每条测试用例;(2)对基于k-序列表示的JUnit测试用例集合进行化简。下面分别介绍这两个步骤的具体过程。(1)使用k_序列的集合表示每条JUnit测试用例首先介绍k_序列表示方法。序列的长度指的是序列中成员的个数。长度为k的 序列称为k-序列,记成[mi,m2,…,mk],其中Hii(KiSk)是这个序列的成员。位于不同 位置的成员有可能是同一方法。比如,k-序列的成员Hii和%(1彡i兴j彡k)可能是同一 方法,只不过它们在这个序列中的位置不同。接着,将每条JUnit测试用例拆分成若干条k-序列,再将每条JUnit测试用例表 示成若干个上述k-序列构成的集合。具体地,形如JUnit测试用例T = [mi,m2,,-,mn]表示测试用例T中有η个方法 Hi1, m2, m3,…,mn被调用,它们的调用顺序是Hli要比Hlj先被调用(i < j)。Α.如果测试用例T只有1个方法被调用,即T = [mj,那么它的序列表示如下眷如果k = 1,T的k-序列表示为{[mj}; 如果k > 1,T的k_序列表示为^ ^^^++們〃]};
於-1个B.如果测试用例T只有2个方法被调用,即T= Dvm2],那么它的序列表示如下 如果 k = 1,T 的 k-序列表示为{[mj,[m2]}; 如果 k = 2,T 的 k-序列表示为{[Iii1, m2]};眷如果k > 2,T 的 k-序列表示为{h,%,f^2++,4^d ;
t一 2个C.否则, 如果2<k<k+l <n,那么,先将T拆分成k-序列[Hi1,…,mk],[m2,…, mk+1], ...,[mn_k+1...,mn],然后T 表示成 Hm1, ...,mk],[m2, ...,mk+1],...,[mn_k+1...,mn] )■;
如果2彡k < k+1 = n,那么先将T拆分成k_序列[Hi1,…,mk],[m2,…,mk+1], 然后将T表示成{[IV…,mk],[m2,…,mk+1]}; 如果2彡k = n,那么先将T拆分成k-序列[Hi1,…,mk],然后将T表示成 {[m” …,mk]}; 如果k = 1,那么先将T拆分成k-序列[Hi1],[m2],…,[mn],然后将T表示成 {[mj , [m2],…,[mn]};參如果k > η > 3,那么先将T拆分成k_序列^” + ++,^^^^++,們〃]’然后将T表
it—η个
示成 t-η个(2)化简基于k-序列表示的JUnit测试用例集合。步骤如下1)根据JUnit测试用例包含的方法数将原测试用例集合T分成两个不相交的子 集T1和T2,T1由方法数少于k的JUnit测试用例构成,T2由方法数不少于k的JUnit测试 用例构成。初始时,化简后的测试用例集合T"为空;2)对于T1中的测试用例,选择具有不同k-序列表示的JUnit测试用例来构造集 合T3。即如果有多条JUnit测试用例具有相同的k-序列表示,从中任选一条JUnit测试 用例放入T3中;3)对于T2中的测试用例,首先统计T2中的所有测试用例的k_序列表示包含的方 法序列构成集合R,使用如贪心算法在内的任一化简算法,从T2中挑选出部分测试用例构成 集合T4,使得R中任意方法序列都至少可以被T4中的某条测试用例对应的k-序列表示包 含;
4)T3和T4两集合的并就是化简后的JUnit测试用例集合T"。利用本发明提出的测试用例化简技术,不仅可以如传统的测试用例化简技术一样 揭示单个方法上的故障,而且还可以揭示由于方法调用顺序不当引起的故障。本发明提出 的测试用例化简技术可以提高化简后测试用例集合的揭错能力,减少测试用例化简过程造 成的测试效果损失。
图1为构造JUnit测试用例的k-序列表示的流程图;图2为化简基于k-序列的JUnit测试用例集合的流程图。
具体实施例方式下面用一个具体例子来对本发明作进一步说明,但本发明的范围并不仅限于该例子。Java 类 IntStack 代码如下public class IntStack{private iht [] store ;private int size ;
private static final int INITIAL_CAPACITY = 10 ;public IntStackO{this, store = new int[INITIAL_CAPACITY];this, size = 0 ;}public void push (int value){if (this, size = = this, store, length){int[]store = new int[this, store. length*2];System, arraycopy (this, store, 0, store, this, size);this, store = store ;}this, store [this, size++] = value ;}public int pop (){return this, store[—this.size];}...}JUnit测试用例代码如下public class Testcases{...public void testl (){IntStack si = new IntStackO ;si. push (5);si. pop ();//Assertion ;}public void test2(){IntStack s2 = new IntStackO ;s2. push (3);//Assertion ;}
public void test3(){IntStack s3 = new IntStackO ;s3. pop ();//Assertion ;}}已知类IntStack的JUnit测试用例集合T中包含testl,test2,和test3这三条 测试用例,本发明的目的在于对JUnit测试用例集合T(Τ = {testl, test2,test3})进行化 简。下面按照上面给出的方案描述详细解释本发明的实施过程。(考虑到IntStack类的特 点,程序员选择k = 2,即程序员只关心由于两个方法调用顺序不当或者单个方法使用不 当引起的错误。)(1)使用2-序列的集合表示这三条测试用例。testl 调用的方法有 IntStackO,push (),禾口 pop (),因此,testl 表示成 {[IntStack (),push () ],[push (), pop () ]}。test2 调用的方法有 IntStack ()禾口 push (), 因此,test2 表示成{[IntStack (), push () ]}。test3 调用的方法有 IntStackO 禾口 pop(),因此,test3 表示成{[IntStack(), pop () ]} ο这三条测试用例包含的方法数目都不小于k(k = 2),因此,将上述三条测试用例 {[IntStackO , push()], [push (), pop () ]}, {[IntStack (), push () ]},禾口 {[IntStackO, pop()]}都放入集合T2中。(2)化简2-序列表示的JUnit测试用例集合。(2. 1)T2中的所有测试用例对应的2-序列表示包含的序列包括[IntStackO, push () ],[push (),pop ()],禾口 [IntStack 0 , pop ()]。因此,集合 R = {[IntStack (), push () ], [push (), pop () ], [IntStack (), pop () ]}。(2. 2)使用贪心算法从T2中选择少量测试用例使得R中的每个2-序列都可以被 选出测试用例对应的2-序列表示包含。使用贪心算法,不难发现testl —定优先被选出, 因为testl可以包含集合R中的两个元素,而test2和test3分别只能包含R中一个元素。 于是,testl被选出放到集合T4中。(2.3)由于 testl 包含序列[IntStack (), push ()]和[push (),pop ()],因此,再从 T2中选择测试用例时,不必再考虑R中的这两个元素。于是,接下来需要再选择测试用例使 之包含R中的另一个元素[IntStackO,pop()]。显然,只有test3能够包含这一序列。于 是test3被选出放到集合T4中。(2. 4)T4包含测试用例testl和test3,并且R中的任意元素(2_序列)都可以被 T4中的测试用例对应的2-序列包含。因此,对于集合T2的化简过程结束。由于1\为空,所 以T3也为空。所以,化简后的测试用例集合T"就是T4本身,S卩T〃 = {testl, test3}0虽然通过实施例详细描述了本发明基于执行序列的JUnit测试用例化简方法,但 是本领域的技术人员应当理解,本发明并不限于实施例中所公开的内容和范围,在不脱离 本发明的实质和精神范围内,可以对本发明进行各种变换、修改和替换。
权利要求
一种JUnit测试用例化简方法,化简后的测试用例是化简前测试用例的真子集,化简后的测试用例的揭错能力与化简前接近,其特征在于化简后的测试用例对方法调用顺序不当导致的故障的揭错能力与化简前相同;化简方法包括以下步骤第一步把JUnit测试用例集合中的每条测试用例都表示成一个k-序列的集合;第二步对第一步中得到的k-序列集合进行化简。
2.如权利要求1所述的方法,其特征在于,第一步的实现方法为先将每条JUnit测试 用例拆分成多条k-序列,再将每条JUnit测试用例表示成多个k-序列构成的集合。
3.如权利要求1或2所述的方法,其特征在于,对形如JUnit的测试用例T=[mi, m2,, ,mn],表示测试用例T中有n个方法n^,m2,m3, ,mn被调用,它们的调用顺序是n^ 要比%先被调用(i < j),则把它表示成k-序列形式的过程如下A.如果测试用例T只有1个方法被调用,即T= [mj,那么它的序列表示如下 如果k= 1,T的k-序列表示为{[mj}; 如果k > 1,T的k-序列表示为;於-1个B.如果测试用例T只有2个方法被调用,即T= [mi, m2],那么它的序列表示如下 如果k= 1,T的k-序列表示为{[mj, [m2]}; 如果k = 2,T的k-序列表示为{[mi,m2]};參如果k > 2,T的k-序列表示为^, ^們〃]};k-2今C.否则, 如果2≤k < k+1 < n,那么,先将T拆分成k-序列:[mi,. [mn_k+1. . . , mn],然后夺 T 表示成{[m” ,mk], [m2, . . . , mk+1],. 如果2≤k < k+1 = n,那么先将T拆分成k-序列[mi, 后将 T 表示成{[m” …,mk], [m2, . . . , mk+1]}; 如果2≤k = n,那么先将T拆分成k-序列0V...,mk],然后将T表示成{[n^,..., mk]}。 如果k = 1,那么先将T拆分成k-序列[mi],[m2],. . .,[mn],然后将T表示成{[mj, [m2], . . . , [mj};參如果k > n > 3,那么先将T拆分成k-序列jA^+Mffe+ff] ’然后将T表示成k-n今{[讲”…,/^,^^^..^^//]}。k-n今
4.如权利要求1所述的方法,其特征在于,第二步的实现步骤为1)根据JUnit测试用例包含的方法数将原测试用例集合T分成两个不相交的子集 和T2,由方法数少于k的JUnit测试用例构成,T2由方法数不少于k的JUnit测试用例 构成,初始时,化简后的测试用例集合T"为空;2)对于中的测试用例,选择具有不同k-序列表示的JUnit测试用例来构造集合T3, 即如果有多条JUnit测试用例具有相同的k-序列表示,从中任选一条JUnit测试用例放 入T3中;3)对于T2中的测试用例,首先统计T2中的所有测试用例的k-序列表示包含的方法序列构成集合R,使用如贪心算法在内的任一化简算法,从T2中挑选出部分测试用例构成集合 T4,使得R中任意方法序列都至少可以被T4中的某条测试用例对应的k-序列表示包含; 4)T3和T4两集合的并就是化简后的JUnit测试用例集合T"。
全文摘要
本发明提供了一种基于执行序列的JUnit测试用例化简方法,属于软件测试中的测试用例化简技术领域。本发明提出了一种k-序列的表示方法来描述每条JUnit测试用例,用以体现每条JUnit测试用例对方法的调用顺序,并将所有JUnit测试用例包含的方法调用序列作为化简前后需要保持不变的条件,对JUnit测试用例集合进行化简,从而保证化简后的测试用例集合可以揭示源于单个方法调用不当和源于多个方法调用顺序不当的错误。本发明提出的测试用例化简技术可以提高化简后测试用例集合的揭错能力,减少测试用例化简过程造成的测试效果损失。
文档编号G06F11/36GK101833508SQ20101016534
公开日2010年9月15日 申请日期2010年5月7日 优先权日2010年5月7日
发明者张令明, 张路, 梅宏, 郝丹 申请人:北京大学