首页 / 专利库 / 软件 / 白盒测试 / 测试用例设计方法和系统

测试用例设计方法和系统

阅读:899发布:2020-07-19

专利汇可以提供测试用例设计方法和系统专利检索,专利查询,专利分析的服务。并且本 发明 公开了一种测试 用例 设计方法,用于 软件 测试,其技术方案包括步骤:A.将程序代码映射为结构对象;B.统计程序路径;C.生成测试用例。本发明还公开了另一种测试用例设计方法,其技术方案是将前述技术方案所述的步骤C用下述步骤代替:D.对程序进行插装;E.编译并运行插装后的程序;F.记录逻辑 覆盖 信息;G.计算逻辑目标的近似测试用例;并可以进一步包括步骤:H.生成 修改 提示。本发明的第一技术方案自动生成各种逻辑覆盖的测试用例集,提高了 白盒测试 的效率。本发明的第二技术方案在已有测试用例的 基础 上,快速设计用于各种逻辑覆盖的测试用例。本发明还公开了可实现上述第二技术方案类似功能的测试用例设计系统。,下面是测试用例设计方法和系统专利的具体信息内容。

1.一种测试用例设计方法,其特征在于,包括步骤:
A.将程序代码映射为结构对象;
B.统计程序路径;
C.生成测试用例。
2.根据权利要求1所述的测试用例设计方法,其特征在于,所述结构对象包 括:语句对象、分支树对象及分支对象。
3.根据权利要求2所述的测试用例设计方法,其特征在于,将程序逻辑结构 分为顺序结构和分支结构;所述语句块对象用于描述顺序结构,所述分支树对象 用于描述分支结构,所述分支对象用于描述顶层分支或分支结构的一个分支;每 一所述分支树对象至少嵌套了两个分支对象。
4.根据权利要求1所述的测试用例设计方法,其特征在于,所述路径包括语 句组合及分支组合。
5.根据权利要求1所述的测试用例设计方法,其特征在于,所述测试用例包 括:提示表达式,所述提示表达式包括:判定式、反判定式、条件式及反条件 式。
6.根据权利要求5所述的测试用例设计方法,其特征在于,所述反判定式是 判定式取反的结果,所述反条件式是条件式取反的结果。
7.根据权利要求6所述的测试用例设计方法,其特征在于,所述取反是指将 表达式中的等于操作符、关系操作符、逻辑操作符用相反的操作符替换,空表达 式取反后仍为空。
8.根据权利要求1至7任一权利要求所述的测试用例设计方法,其特征在 于,所述步骤A具体包括:解析所述程序代码的逻辑结构,依据所述程序代码的 分支结构生成对应的分支树对象及对应的分支对象,依据所述程序代码的顺序结 构生成对应的语句块对象,并将所述分支树对象和所述语句块对象嵌套于对应层 次的分支对象中。
9.根据权利要求1至7任一权利要求所述的测试用例设计方法,其特征在 于,所述步骤B具体包括:后序扫描所述结构对象,针对每一结构对象,将一个 输入路径集作为初始数据进行路径统计,顶层分支对象的输入路径集只含一条空 路径;针对语句块对象,在输入路径集的每条路径中记录该语句块名;针对分支 对象,在输入路径集的每条路径中记录该分支名,前一子对象的输出路径集作为 下一子对象的输入路径集;针对分支树对象,将输入路径集的拷贝作为每一子对 象的输入路径集。
10.根据权利要求9所述的测试用例设计方法,其特征在于,所述步骤B进一 步包括:当路径经过含有返回语句的语句块对象时,该路径即结束。
11.根据权利要求9所述的测试用例设计方法,其特征在于,所述步骤B进一 步包括:忽略隐藏的对象及隐藏的对象的直接或间接子对象。
12.根据权利要求1至7任一权利要求所述的测试用例设计方法,其特征在 于,用下述步骤计算分支的判定式:
空分支或ELSE分支或DEFAULT分支或顶层分支的判定式为空;
DO...WHILE结构的两个分支的判定式均为空;
CASE分支用SWITCH表达式与常量表达式组成等式作为判定式;
FOR分支用条件表达式作为判定式,多个条件表达式用逻辑与连接,并可用 条件变量的初始值代替该条件变量;
其他分支用判定中的条件表达式作为判定式。
13.根据权利要求1至7任一权利要求所述的测试用例设计方法,其特征在 于,所述步骤C具体包括下述步骤中的任一步骤:
C1.生成路径覆盖测试用例;
C2.生成语句覆盖测试用例;
C3.生成判定覆盖测试用例;
C4.生成条件值组合覆盖测试用例;
C5.生成条件式覆盖测试用例;
C6.生成条件值覆盖测试用例。
14.根据权利要求13所述的测试用例设计方法,其特征在于:
所述步骤C1具体包括:针对程序的每一路径,执行用于生成一条路径的覆盖 测试用例的步骤;
所述步骤C2具体包括:筛选可覆盖全部语句的最小数量的目标路径;针对每 一所述目标路径,执行用于生成一条路径的覆盖测试用例的步骤;
所述步骤C3具体包括:筛选可覆盖全部分支的最小数量的目标路径;针对每 一所述目标路径,执行用于生成一条路径的覆盖测试用例的步骤;
所述步骤C4具体包括:针对每一分支的每一条件值组合,执行用于生成一个 条件值组合的覆盖测试用例的步骤;
所述步骤C5具体包括:针对每一分支,选择可覆盖该分支全部条件式的最小 数量的目标条件值组合;针对每一所述目标条件值组合,执行用于生成一个条件 值组合的覆盖测试用例的步骤;
所述步骤C6具体包括:针对每一分支,选择可覆盖该分支全部条件值的最小 数量的目标条件值组合;针对每一所述目标条件值组合,执行用于生成一个条件 值组合的覆盖测试用例的步骤。
15.根据权利要求14所述的测试用例设计方法,其特征在于,所述用于生成 一条路径的覆盖测试用例的步骤具体包括:针对所述路径的每一经历分支,依次 选择该经历分支的在前姐妹分支的反判定式,及该经历分支自身的判定式。
16.根据权利要求14所述的测试用例设计方法,其特征在于,所述用于生成 一个条件值组合的覆盖测试用例的步骤具体包括:选择一条经历该条件值组合的 路径作为目标路径;针对该目标路径的每一前导分支,依次选择该前导分支的在 前姐妹分支的反判定式,及该前导分支自身的判定式;针对该条件值组合,依次 选择取真值的条件的条件式,及取假值的条件的反条件式,忽略不可达条件。
17.根据权利要求14所述的测试用例设计方法,其特征在于,所述步骤C进 一步包括:用于将测试用例化简的步骤。
18.一种根据权利要求1所述的测试用例设计方法,其特征在于,用下述步骤 代替所述步骤C:
D.对程序进行插装;
E.编译并运行插装后的程序;
F.记录逻辑覆盖信息;
G.计算逻辑目标的近似测试用例。
19.根据权利要求18所述的测试用例设计方法,其特征在于,所述近似测试 用例是已有测试用例。
20.根据权利要求18或19所述的测试用例设计方法,其特征在于,用于插装 的插装函数包括:语句监视函数;所述语句监视函数用于监视语句的执行。
21.根据权利要求20所述的测试用例设计方法,其特征在于,所述插装函数 进一步包括:条件监视函数;所述条件监视函数用于监视条件的计算或计算结 果。
22.根据权利要求21所述的测试用例设计方法,其特征在于,所述条件监视 函数的插装位置是条件式的两端。
23.根据权利要求18或19所述的测试用例设计方法,其特征在于,所述步骤 F具体包括步骤:记录语句覆盖信息;统计已覆盖路径及已覆盖路径的覆盖用例。
24.根据权利要求23所述的测试用例设计方法,其特征在于,所述步骤F进 一步包括步骤:记录条件覆盖信息。
25.根据权利要求18或19所述的测试用例设计方法,其特征在于,所述步骤 G具体包括下述步骤中的任一步骤:
G1.计算目标路径的近似测试用例;
G2.计算目标分支的近似测试用例;
G3.计算目标语句的近似测试用例;
G4.计算目标条件值组合的近似测试用例;
G5.计算目标条件式的近似测试用例;
G6.计算目标条件值的近似测试用例。
26.根据权利要求25所述的测试用例设计方法,其特征在于:
所述步骤G1具体包括:执行用于计算目标路径的近似路径的步骤;所述目标 路径的近似测试用例等于该目标路径的近似路径的覆盖用例;
所述步骤G2具体包括:选择所有经历目标分支的路径作为候选目标路径;计 算每一所述候选目标路径的近似路径;选择临界差最小的候选目标路径作为目标 路径;所述目标分支的近似测试用例等于所述目标路径的近似路径的覆盖用例;
所述步骤G3具体包括:所述目标语句的近似测试用例等于该目标语句所在分 支的近似测试用例;
所述步骤G4具体包括:执行用于计算目标条件值组合的近似测试用例的步骤 计算所述目标条件值组合的近似测试用例;
所述步骤G5具体包括:选择所有目标条件式可达的条件值组合作为候选目标 条件值组合;计算每一所述候选目标条件值组合的近似测试用例;选择已覆盖的 在前条件式最多的候选条件值组合作为目标条件值组合;所述目标条件式的近似 测试用例等于所述目标条件值组合的近似测试用例;
所述步骤G6具体包括:选择所有包含目标条件值的条件值组合作为候选目标 条件值组合;计算每一所述候选目标条件值组合的近似测试用例;选择已覆盖的 在前条件值最多的候选条件值组合作为目标条件值组合;所述目标条件值的近似 测试用例等于所述目标条件值组合的近似测试用例。
27.根据权利要求26所述的测试用例设计方法,其特征在于:所述用于计算 目标路径的近似路径的步骤具体包括:比较目标路径与各已覆盖路径的分支组 合,重叠分支最多的已覆盖路径,就是目标路径的近似路径;所述用于计算目标 条件值组合的近似测试用例的步骤具体包括:选择所有覆盖了目标分支的测试用 例作为候选测试用例;选择相符条件值最多的候选测试用例作为目标条件值组合 的近似测试用例。
28.根据权利要求18所述的测试用例设计方法,其特征在于,进一步包括步 骤:
H.生成修改提示。
29.根据权利要求28所述的测试用例设计方法,其特征在于,所述修改提示 包括:提示表达式。
30.根据权利要求29所述的测试用例设计方法,其特征在于,所述修改提示 包括待满足条件,也可以进一步包括已满足条件。
31.根据权利要求28所述的测试用例设计方法,其特征在于,所述步骤H具 体包括下述步骤中的任一步骤:
H1.生成目标路径或目标语句或目标分支的近似测试用例的修改提示;
H2.生成目标条件值组合或目标条件式或目标条件值的近似测试用例的修改 提示。
32.根据权利要求31所述的测试用例设计方法,其特征在于:
所述步骤H1具体包括:针对目标路径的每一经历分支,依次选择该经历分支 的在前姐妹分支的反判定式,及该经历分支自身的判定式;
所述步骤H2具体包括:选择一条经历目标分支的已覆盖路径作为目标路径, 针对该目标路径的每一前导分支,依次选择该前导分支的在前姐妹分支的反判定 式,及该前导分支自身的判定式;针对目标条件值组合,依次选择取真值的条件 的条件式,取假值的条件的反条件式,忽略不可达条件。
33.根据权利要求31所述的测试用例设计方法,其特征在于:
所述步骤H1具体包括:针对目标路径的每一经历分支,依次选择该经历分支 的在前姐妹分支及该经历分支自身的提示表达式,其中,阻塞前或临界前的分支 按下述步骤选择提示表达式:依据该分支在近似测试用例的条件值组合,选择条 件值为真的条件的条件式,条件值为假的条件的反条件式,忽略不可达条件;其 他分支按下述步骤选择提示表达式:在前姐妹分支选择反判定式,经历分支自身 选择判定式;
所述步骤H2具体包括:选择一条经历目标分支的已覆盖路径作为目标路径, 针对该目标路径的每一前导分支,依次选择该前导分支的在前姐妹分支及该前导 分支自身在近似测试用例的条件值组合中取真值的条件的条件式,取假值的条件 的反条件式,忽略不可达条件;针对目标条件值组合,依次选择取真值的条件的 条件式,取假值的条件的反条件式,忽略不可达条件。
34.根据权利要求32或33所述的测试用例设计方法,其特征在于,所述步骤 H1进一步包括:忽略阻塞分支之后的分支;所述步骤H2进一步包括:忽略目标 条件及目标条件后的条件。
35.根据权利要求32或33所述的测试用例设计方法,其特征在于:
所述步骤H1进一步包括:阻塞前或临界前所选择的提示表达式属已满足条 件,其他属待满足条件;
所述步骤H2进一步包括:针对目标路径选择的提示表达式属已满足条件;针 对目标条件值组合选择的提示表达式,条件值已被近似测试用例所覆盖的条件对应 的提示表达式属已满足条件,其他属待满足条件。
36.根据权利要求35所述的测试用例设计方法,其特征在于:所述步骤H1 或H2进一步包括:忽略已满足条件。
37.根据权利要求32或33所述的测试用例设计方法,其特征在于:所述步骤 H进一步包括:用于将修改提示化简的步骤。
38.根据权利要求29所述的测试用例设计方法,其特征在于:所述修改提示 进一步包括提示代码。
39.根据权利要求18所述的测试用例设计方法,其特征在于,进一步包括步 骤:
I.统计逻辑覆盖。
40.根据权利要求39所述的测试用例设计方法,其特征在于,所述步骤I具 体包括下述步骤中的任一步骤:
I1.统计路径覆盖;
I2.统计语句覆盖;
I3.统计分支覆盖;
I4.统计条件式覆盖;
I5.统计条件值覆盖;
I6.统计条件值组合覆盖。
41.一种测试用例设计系统,其特征在于,包括:
用于将程序代码映射为结构对象的装置;
用于统计程序路径的装置;
用于记录逻辑覆盖信息的装置;
用于计算逻辑目标的近似测试用例的装置。
42.根据权利要求41所述的测试用例设计系统,其特征在于,进一步包括:
用于对程序进行插装的装置。
43.根据权利要求41或42所述的测试用例设计系统,其特征在于,进一步包 括:
用于生成修改提示的装置。
44.根据权利要求43所述的测试用例设计系统,其特征在于,进一步包括:
用于统计逻辑覆盖的装置。

说明书全文

技术领域

发明涉及软件测试领域,更具体地,涉及软件测试领域的测试用例设计方 法和测试用例设计系统。

背景技术

软件测试的方法主要有黑盒测试白盒测试。黑盒测试又叫功能测试,一般 根据程序的功能要求来设计测试用例。白盒测试依据程序的内部逻辑结构,一般 采用逻辑覆盖法设计测试用例。测试用例(Test Case)目前没有经典的定义,一 个测试用例,一般是指一个测试任务,该任务在设定的条件下执行被测试程序。 描述测试用例的方式也没有统一标准,大体上可以分为两类:不可执行的测试用 例和可执行的测试用例,不可执行的测试用例用文字、表格或其他方式说明程序 的功能或相关数据的范围等,一般作为进行测试的规范或作为进一步编写可执行 测试用例的依据;可执行的测试用例是可编译执行或解释执行的代码及数据,或 用电子表格、数据库等存储的有规范格式的、可用以生成可执行的代码的数据。
白盒测试常用的逻辑覆盖有:语句覆盖、判定覆盖、表达式覆盖、条件覆 盖、判定条件覆盖、条件值组合覆盖、路径覆盖,分别定义如下:
1.语句覆盖:设计足够的测试用例,使每一可执行语句至少执行一次。
2.判定覆盖:又叫分支覆盖,设计足够的测试用例,使每个判定的取真分支 和取假分支至少经历一次。
3.表达式覆盖(条件式覆盖):设计足够的测试用例,使每个判定的每个条件 至少计算一次。
4.条件覆盖(条件值覆盖):设计足够的测试用例,使每个判定的每个条件的 所有可能取值至少执行一次。
5.判定条件覆盖:设计足够的测试用例,使每个判定中每个条件的所有可能 取值至少执行一次,同时,判定的取真分支和取假分支至少经历一次。
6.条件组合覆盖(条件值组合覆盖):设计足够的测试用例,使每个判定的所 有可能的条件取值的组合至少执行一次。
7.路径覆盖:设计足够的测试用例,使程序中所有可能的路径至少执行一 次。程序中含有循环结构时,一个很简单的程序都可能产生大量的路径,完全的 路径覆盖在实际的测试工作中不具实用性,因此,对于路径覆盖,统计路径时一 般不考虑循环的实际次数,只考虑至少执行循环体一次和不执行循环体两种情 况,这种简化的路径覆盖又叫Z路径覆盖,由于完全的路径覆盖不具实用性,我 们所说的路径覆盖是指Z路径覆盖。
从上述各种逻辑覆盖的定义可看出:表达式覆盖、条件覆盖、判定条件覆 盖、条件组合覆盖均与条件有关,其中判定条件覆盖是判定覆盖与条件覆盖的组 合,可以用判定覆盖加条件覆盖的方式完成判定条件覆盖,因此,我们把判定条 件覆盖看成是一种测试完整性的度量方法而不是一种测试用例设计方法,不对判 定条件覆盖作进一步描述;表达式覆盖、条件覆盖、条件组合覆盖这三种逻辑覆 盖名称不太准确,进行深入的描述时容易混洧、难于理解,由于表达式覆盖的逻 辑目标是条件表达式,我们把表达式覆盖称为条件式覆盖;由于条件覆盖的逻辑 目标是条件的可能取值,我们把条件覆盖称为条件值覆盖;由于条件组合覆盖的 逻辑目标是条件可能取值的组合,我们把条件组合覆盖称为条件值组合覆盖,即 采用上述定义中括号内的名称。
每种逻辑覆盖都有其优缺点,总体来说,排在后面的逻辑覆盖,测试的完整 性较高,当然需要的测试用例也更多,测试成本也更高。
白盒测试方法要求测试人员充分理解程序的逻辑结构,一般过程是根据程序 逻辑结构画出程序逻辑结构图,如程序流程图控制流图,对照程序逻辑结构图 设计测试用例。由于需要理解和分析程序逻辑结构,白盒测试对测试人员的要求 较高,并且需要较高的时间成本。
黑盒测试依据程序的功能要求来设计测试用例,以功能覆盖率衡量测试完整 性,白盒测试依据程序逻辑结构设计测试用例,用逻辑覆盖率衡量测试完整性, 两者各有侧重,不能互相替代,但两者也有内在的联系,例如:黑盒测试也完成 了一定的逻辑覆盖率,白盒测试的覆盖率也可用以检验黑盒测试的完整性,进行 黑盒测试后,如果某些代码未覆盖,很可能是这些代码相关的功能点未被测试 到。黑盒测试针对程序功能进行测试,是软件测试不可缺少的方面,如果程序的 基本功能都不正确,其他方面就更无从谈起,因此,程序测试时一般先进行黑盒 测试,在此基础上再进行适当的白盒测试。
由于黑盒测试也完成了一定的逻辑覆盖率,因此,如果先依据程序功能进行 黑盒测试,再检查逻辑覆盖率,根据未覆盖的逻辑单位,添加测试用例进行测 试,则可以减少重复工作,降低测试成本,但实际上,由于逻辑覆盖具有逾后逾 难的特点,即开始时数量较少的测试用例就可以令覆盖率迅速提高,越到后来, 设计用于完成剩余覆盖率的测试用例就越难,而且,功能测试所实际完成的逻辑 覆盖往往是最容易覆盖的部分。要达到理想的白盒测试覆盖率,就现有技术而 言,测试成本很高。
事实上,虽然充分的黑盒测试和白盒测试是提高软件质量的必要手段,但目 前的软件开发中,进行了比较充分测试的并不多,尤其是进行了充分的白盒测试 的更少,特别是国内的中小软件开发企业,多数并未进行实际的白盒测试,造成 这一局面的原因之一就是白盒测试的成本太高,达到较高完整性的白盒测试的成 本往往是软件开发企业难于承受的。

发明内容

本发明要解决的技术问题是针对白盒测试成本太高的问题,提出一种低成本 高效率的设计白盒测试用例的方法。
本发明要解决的另一个技术问题是针对白盒测试逾后逾难的问题,提出一种 在已有测试用例的基础上,快速设计用于各种逻辑覆盖的测试用例的方法和系 统。
为了解决上述第一个技术问题,本发明提出的技术方案是:
一种测试用例设计方法,其特征在于,包括步骤:
A.将程序代码映射为结构对象;
B.统计程序路径;
C.生成测试用例。
为了解决上述第二个技术问题,本发明提出的技术方案是:
一种根据上述第一技术方案的测试用例设计方法,其特征在于,用下述步骤 代替所述步骤C:
D.对程序进行插装;
E.编译并运行插装后的程序;
F.记录逻辑覆盖信息;
G.计算逻辑目标的近似测试用例。
还可以进一步包括下述步骤:
H.生成修改提示。
为了解决上述第二个技术问题,本发明提出的另一技术方案是:
一种测试用例设计系统,其特征在于,包括:
用于将程序代码映射为结构对象的装置;
用于统计程序路径的装置;
用于记录逻辑覆盖信息的装置;
用于计算逻辑目标的近似测试用例的装置。
还可以进一步包括:
用于生成修改提示的装置。
本发明的第一个技术方案自动生成测试用例。该技术方案可以生成各种逻辑 覆盖的测试用例集,测试人员不需要分析程序的逻辑结构,不需要画出任何图 表,依据自动生成的测试用例即可确定测试输入数据,编写测试代码进行测试。 由于不需人工分析程序的逻辑结构和画出图表,本发明降低了对白盒测试的人员 要求并提高了白盒测试的效率,可在较低的成本耗费下,完成具有很高完整性的 白盒测试,有利于提高软件质量、降低开发成本。
本发明的第二个技术方案和第三个技术方案在已有测试用例中,计算出可覆 盖预期逻辑目标的近似测试用例,对该近似测试用例进行少量的修改,即可覆盖 预期逻辑目标。该技术方案还可以提出修改提示,指出需修改哪些数据及数据的 范围或需满足的条件,使修改工作高效准确。本发明可在黑盒测试的基础上,快 速完成白盒测试,并通过白盒测试来验证黑盒测试的完整性。已有测试用例越 多,近似测试用例就越接近预期逻辑目标的覆盖要求,所需修改就越少,因此, 本发明的第二个和第三个技术方案彻底克服了白盒测试的逾后逾难的特点,也可 以用以纯粹的白盒测试。
附图说明
下面结合附图对本发明的具体实施方式作进一步详细的说明:
图1是本发明的一个实施例的总体流程图。
图2是在本发明的一个实施例,各结构对象的内部数据构成的示意图及结构 对象树示意图,其中图2A是语句对象的内部数据构成示意图,图2B是分支树 对象的内部数据构成示意图,图2C是分支对象的内部数据构成示意图,图2D是 结构对象树示意图。
图3是示例代码及代码片分类示例。
图4是将代码片映射为结构对象的流程示意图。
图5是统计程序路径的流程示意图,其中,图5A是当对象为语句块时统计路 径的流程示意图,图5B是当对象为分支时统计路径的流程示意图,图5C是当对 象为分支树时统计路径的流程示意图。
图6是生成一条路径的覆盖测试用例的流程示意图。
图7是依据条件值组合生成测试用例的一部分的流程示意图。
图8是本发明另一个实施例的总体流程图。
图9是本发明再一个实施例的总体构成示意图。

具体实施方式

图1是本发明的一个实施例的总体流程图,如图1所示,步骤A将程序代码 映射为结构对象;步骤B统计程序路径;步骤C生成测试用例。
下面详细描述图1所示的步骤A,首先详细描述步骤A所述的结构对象,结 构对象用于描述程序的逻辑结构。
本实施例把程序逻辑结构分为两种:顺序结构和分支结构。顺序结构对应于 一个语句序列,在这个语句序列中,如果第一条语句执行了,那么在没有发生异 常,也未因返回语句提前返回的情况下,其他所有语句也会执行,符合这一条件 的所有连续的语句应视为属于同一个顺序结构而不能分拆,即不能把其中的一部 分视为属于一个顺序结构,把另一部分视为属于另一个顺序结构。顺序结构具有 一个入口点和一个出口点,其入口点为结构中的第一条语句,出口点为结构中的 最后一条语句,但如果顺序结构中的某条语句是返回语句(如C++的return语 句),执行到该语句时函数即返回,后面的语句不会执行,实际上,后面的语句是 无效的,因此,该语句是该顺序结构的实际出口点。由于GOTO语句(如C++的 goto语句)破坏了结构化设计并且在当今的开发中使用越来越少,因此,本实施例 不考虑GOTO语句。
分支结构对应于一个语句序列,在这个语句序列中,含有判断和/或跳转语句 或类似功能的语句,在不同的条件下,可能会执行或不执行或重复执行其中的某 些语句。最典型的分支结构是选择结构,循环结构也属于分支结构。由于分支结 构在不同的条件下会执行或不执行或重复执行某些语句,所以,分支结构至少包 含两种可能的执行路线,这些执行路线叫做分支,也就是说,一个分支结构至少 包含两个分支。为了简化问题,循环结构视为具有进入循环体和不进入循环体两 个分支,不考虑循环的次数。
比较常用的选择结构有:
IF结构,如C/C++/Java的if(…)…/else…;Pascal的if…then…else…;Basic 的IF…THEN…END IF;该结构可含或不含ELSE分支,ELSE分支之前可以增加 不限数量的ELSE IF分支。
SWITCH结构,如C/C++/Java的switch(…)…,Pascal的case…of…,Basic 的SELECT CASE…,该结构可含多个CASE分支,可含也可不含DEFAULT分 支。
比较常用的循环结构有:
FOR结构:如C/C++/Java的for(…)…,Pascal的for…do…,Basic的FOR… NEXT和FOR EACH…NEXT。
WHILE结构:如C/C++/Java的while(…)…,Pascal的while…do…,Basic的 DO WHILE…LOOP,DO UNTIL…LOOP。
Do…WHILE结构:如C/C++/Java的do…while(…),Basic的DO…LOOP WHILE…,DO…LOOP UNTIL…,该结构至少执行循环体一次。
上述分支结构和编程语言的示例并非穷举,凡具有两个或两个以上执行路线 的代码结构,都视为分支结构。
如上所述,循环结构视为具有进入循环体和不进入循环体两个分支,不考虑 循环的次数,而Do…WHILE循环结构至少执行循环体一次,因此,它的不进入 循环体的分支是不可达的。
分支结构也具有一个入口点和一个出口点,不论其内部的执行路线如何,在 不发生异常的前提下,总是由入口点进入该结构,并由出口点离开该结构,这里 有一个特例,如果结构内含有返回语句,执行到该语句时函数即返回,而不会从 出口点离开该分支结构。
有些分支结构的某些分支是隐含的,如IF结构,如果最后没有ELSE分支, 则包含一个隐含的分支,即使含有ELSE IF分支也是如此,此隐含的分支的执行 条件和路线是:当IF和所有ELSE IF判定均为假时,直接跳转到结构的出口点。 含有隐含分支的情况还有:循环结构的不进入循环体分支,该分支的执行条件和 线路是:第一次进行循环条件判断时,该条件即为假,直接跳转到结构的出口 点;SWITCH结构,当不含DEFAULT分支时,也含有一个隐含的分支,其执行 条件和路线是:所有CASE分支的条件均不满足,不执行任一CASE分支,直接 跳转到结构的出口点。
由于每一分支结构至少包含两条分支,可以说,分支结构是由分支构成的。 分支包含两方面内容:分支判定和分支体,分支判定的计算结果一般只有真和假 两个值。判定为真时,执行分支体,否则不执行分支体。隐含分支的分支判定和 分支体都是空的。对于某一分支来说,其分支体具有一定的范围,称为作用域, 一般使用特定的符号来定义作用域的开始和结束,例如:C/C++用花括号({}), PASCAL用begin和end来指定作用域的开始和结束。作用域内的所有语句,不 论其结构如何,数量多少,均属于该分支体,因此,一个分支的分支体可以包含 一个或多个顺序结构,也可以包含一个或多个分支结构,我们称为子结构,子结 构又可以包含自己的子结构。
综上所述,本实施例把程序逻辑结构分为分支结构和顺序结构,一个分支结 构至少包含两个分支,每一分支又可以进一步包含顺序结构和/或分支结构,我们 把这种包含称为嵌套,嵌套的层次和数量没有限制。分支结构和顺序结构均有一 个入口点和一个出口点,程序执行到任一结构时,在未发生异常的情况下,总是 从入口点进入该结构,从出口点离开该结构,除非因执行到返回语句而提前返 回。
本实施例用结构对象来对应描述上述程序逻辑结构:用分支树对象描述分支 结构,用分支对象描述分支结构中的一个分支,用语句块对象描述顺序结构。其 中,分支树对象嵌套至少两个分支对象,分支对象可以嵌套任意数量的分支树对 象和/或语句块对象,嵌套的层次和数量没有限制,语句块对象不嵌套其他对 象。另外,本实施例把目标程序的整体视为一个分支,称为顶层分支,用一个顶 层分支对象来描述,该顶层分支对象与其他分支对象不同的是,它不嵌套于其他 对象。后文所述“分支对象”,包括顶层分支对象和其他层次的分支对象。我们把 分支树对象、分支对象、语句块对象统称为结构对象。
如果对象A嵌套了对象B,我们把对象A称为对象B的父对象,对象B称为 对象A的子对象。从对象的内部数据的关系来说,对象A(父对象)嵌套对象B (子对象),是指对象A保存了对象B本身或对象A保存了对象B的指针或引用, 或对象A保存了可以引用到对象B的其他数据,通过对象A可以引用对象B。语 句块对象没有子对象,分支对象也可能没有子对象。顶层分支对象没有父对象, 其他分支对象的父对象为分支树对象;分支树对象和语句块对象的父对象都是分 支对象(包括顶层分支对象);我们把语句块对象的父对象称为该语句块所在的分 支。
图2是在本实施例,上述各对象的内部数据构成的示意图及结构对象树示意 图,其中图2A是语句块对象的内部数据构成示意图,图2B是分支树对象的内部 数据构成示意图,图2C是分支对象的内部数据构成示意图,图2A到图2C中, 实线画出的是固定的组成部分,点划线画出的是可有可无并且不限数量的组成部 分,图2D是结构对象树示意图。
图2A是语句块对象的内部数据构成示意图,如图2A所示,语句块对象有一 个代码字段,用于储存它所对应的程序代码,并有一个名称字段,用于识别不同 的语句块对象,名称可以使用字母表示,如‘a’、‘b’、‘c’。
图2B是分支树对象的内部数据构成示意图,如图2B所示,分支树对象至少 嵌套了两个分支对象,还可以嵌套更多的分支对象。分支结构中的每一分支实际 上是该分支结构的不可分割的组成部分,没有这些分支,分支结构也就不存在, 将分支独立出来作为一个对象来处理,仅是为了描述和实施上的简便,同时也更 符合面向对象的思想。本实施例为对应于SWITCH结构的分支树增加一个保存外 围代码的字段,称为外围代码字段,用于保存类似于switch(…)的外围代码,但不 保存作用域开始符和结束符,我们把对应于SWITCH结构的分支树称为特殊分支 树。
图2C是分支对象的内部数据构成示意图,如图2C所示,分支对象有一个分 支判定字段用于储存它对应的分支判定,顶层分支没有对应的分支判定,因此该 字段为空。分支对象可以嵌套任意数量的分支树对象和/或语句块对象,如果没有 嵌套分支树对象和语句块对象,则该分支对象称为空分支对象,与语句块对象一 样,分支对象还具有一个名称字段,用于识别不同的分支对象,名称可以使用字 母表示,如‘a’、‘b’、‘c’。
上述结构对象构成了树状关系,称为结构对象树。图2D是结构对象树示意 图,由图3A所示的代码映射获得的结构对象组成。
为了遍历上述每一结构对象,可对上述结构对象树进行后序扫描或前序扫 描,后序扫描是指:从顶层分支对象开始计算,针对每一对象,先递归计算它的 每一个子对象,子对象计算完成后,再计算该对象自身,由于语句块对象和空分 支对象没有子对象,计算它们时直接计算自身,因此它们是递归终止条件。前序 扫描与后序扫描相比,唯一区别在于,针对每一对象,前序扫描先计算该对象自 身,再递归计算子对象。
图1所示的步骤A将程序代码映射为结构对象,具体包括:解析程序代码的 逻辑结构,依据程序代码的分支结构生成对应的分支树对象及对应的分支对象, 依据程序代码的顺序结构生成对应的语句块对象,并将所述分支树对象和所述语 句块对象嵌套于对应层次的分支对象中,进一步详细描述如下:
首先,将程序代码分解为代码片。所述代码片是指以结构特征来确定类别的 代码单位,代码片类别有:判定、域符号、语句块,域符号又分为域开始和域结 束。判定是指含有判断或跳转或类似关键字、用于控制其作用域内的语句执行或 不执行的代码片,例如C++的if(…)、else if(…)、else、while(…)、switch(…)、case N;Basic的IF…、ELSE IF…、ELSE、DO WHILE…。判定必须完整,例如,C+ +的if(…)是一个完整的判定,不论括号内的条件有多长,都属于该判定的组成部 分,不能分拆。域符号是定义判定的作用域的代码,域开始紧接着判定,用于指 定判定的作用域的开始,域结束用于指定判定的作用域的结束,典型的域符号如 C++的“{”与“}”,PASCAL的“begin”与“end”;语句块是指对应于前文所 述的顺序结构的代码序列,其中不能含有判定。位于某一代码片内的注释可忽略 也可作为该代码片的一部分,位于代码片外的注释可忽略也可归于其后的代码 片。图3B是代码片分类示例,如图3B所示,代码301、303、305对应的代码片 为判定;代码302和307对应的代码片为域符号,其中代码302对应的代码片为 域开始,代码307对应的代码片为域结束;代码304、306、308对应的代码片为 语句块。
本实施例使用包含代码内容、类别、附加类别三个字段的数据结构来存储代 码片,代码片保存在如链表或数组之类的数据容器中。分解代码时,针对判定类 代码片,应判断是不是属于特殊分支树,及判断是不是属于一个分支树的后续分 支,可根据判定的关键字分辨是否属于特殊分支树,如C++代码的switch关键 字;后续分支也可根据判定的关键字来辨识,如针对C++代码,如果是else关键 字引出的判定或else if关键字引出的判定,则属于后续分支,如果一个判定类代码 片属于特殊分支树或后续分支(两者不可能并列),则记录在附加类别中。
有时,域符号是省略的,如C++代码,当作用域只有一条语句时,域符号是 可省略的,再如,Basic的IF…THEN…结构中,THEN后不换行,其作用域为同 一行的THEN后的语句,THEN是域开始,域结束省略;IF…THEN…END IF结 构中,THEN和END IF是域开始和域结束,而IF…THEN…ELSE IF…THEN… ELSE…END IF结构中,ELSE IF之前省略了域结束,ELSE之前也省略了域结 束。代码分解时,每个判定之后应保证具有匹配的域开始和域结束,凡域符号省 略的,应补上相应的域符号,其代码为空。
分解代码时还要考虑隐含分支,当IF结构缺少ELSE分支,SWITCH结构缺 少DEFAULT分支时,以及视为分支结构的循环结构,均含有隐含分支。应为隐 含分支加上三个代码片:一个判定,一个域开始,一个域结束,它们的代码均为 空。
不同的编程语言,代码分解依据的语法及关键字略有不同,具体分解过程可 用编译技术中的词法分析和语法分析技术来实现,实现过程属于现有技术,在此 不作详述。
完成代码分解后,进一步将代码片映射为结构对象。图4是本实施例将代码 片映射为结构对象的流程示意图,如图4所示,401是输入的父对象,流程中所生 成的分支树对象和语句块对象均嵌套于父对象中,父对象只能是分支对象。402是 代码片队列,将代码片按代码的本来顺序,用先进先出的队列储存,称为代码片 队列。后文所述的“弹出代码片”,是指从代码片队列中取出最前的一个代码片, 并将该代码片从代码片队列中删除;后文所述“代码片”,当未作限定时,是指最 新弹出的代码片;后文所述“压入临时队列”,是指将代码片保存到临时代码片队 列的尾部。本实施例将图4所示的流程编写为一个递归调用的函数,用参数方式 传递父对象和代码片队列,初始调用时,生成一个顶层分支对象作为父对象,代 码片队列包含程序的所有代码片,当处理一个分支时,为了进一步处理分支体所 对应的代码片,将该分支作为父对象,该分支的分支体对应的代码片保存在一个 临时代码片队列中作为输入的代码片队列,进行递归调用。
步骤403判断代码片队列是否为空,如果为空则结束,否则执行步骤404,步 骤404弹出代码片,在步骤405判断该代码片的类别,如类别为语句块,执行步 骤411,如类别为判定,执行步骤421,如类别为域符号,由于此时不应该出现域 符号,执行步骤490,步骤490报告错误并退出。
步骤411生成一个语句块对象,并嵌套在父对象中,本实施例在生成语句块 对象时使用一个自动递增的字符变量作为每一个语句块对象的名称,如‘a’、 ‘b’、‘c’。步骤412保存代码,将代码片的代码内容拷贝到语句块对象的代码字 段中,然后返回到步骤403处理下一代码片。
步骤421生成分支树对象,并嵌套到父对象中,在步骤422中根据代码片的 附加类别判断该分支树是否属于特殊分支树,如果是特殊分支树,执行步骤431, 否则执行步骤441。步骤431保存外围代码,将代码片的代码内容拷贝到特殊分支 树对象的外围代码字段。步骤432判断代码片队列是否为空,如果为空则执行步 骤490报错并退出,否则执行步骤433弹出代码片,并在步骤434判断该代码片 的类别,如果类别为域开始,则返回执行步骤432(忽略外围代码的域开始,步骤 472忽略外围代码的域结束),如果类别为判定则执行步骤441,如果类别不是域 开始也不是判定,则执行步骤490报错并退出。
步骤441生成一个分支对象,嵌套于步骤421生成的分支树对象中,本实施 例在生成分支对象时使用一个自动递增的字符变量作为每一个分支对象的名称, 如‘a’、‘b’、‘c’。步骤442保存分支判定,将代码片的代码内容拷贝到该分支 对象的分支判定字段。步骤443判断代码片队列是否为空,如果为空则执行步骤 490报错并退出,否则执行步骤445弹出代码片,并在步骤446判断该代码片的类 别,如果类别是域开始,则执行步骤447,否则执行步骤490报错并退出。步骤 447生成一个用于判断域符号是否匹配的变量N并赋值为1,表示读到了一个域开 始,步骤451判断代码片队列是否为空,如果为空则执行步骤490报错并退出, 否则执行步骤452弹出代码片,并在步骤453中判断该代码片的类别,如果类别 是域开始,则N加1,如果是域结束,则N减1,然后判断N的值是否为0,如果 为0,表示对应的域结束已弹出,实现了域匹配,执行步骤462,否则在步骤454 将代码片压入临时队列,并返回步骤451循环处理下一代码片。步骤462处理分 支体代码,将步骤441生成的分支对象作为父对象,临时队列作为代码片队列, 进行递归调用,然后清空临时队列。
步骤463判断代码片队列是否为空,如果为空则结束,否则在步骤471弹出 代码片,并在步骤472判断该代码片的类别,如果类别是域结束,则返回执行步 骤471,如果类别是判定,则执行步骤473,否则返回执行步骤405处理后续的代 码片直到结束。步骤473根据代码片的附属类别判断该代码片是否属于上一分支 的后续分支,如是则执行步骤441,否则表示当前的分支树已处理完毕,返回执行 步骤405处理后续的代码片直到结束。
下面详细描述图1所示的步骤B,该步骤统计程序路径。路径是指程序的执行 路线,本实施例所述的路径包括:语句组合和分支组合,也就是说,用语句组合 和分支组合来描述路径。语句组合是指路径所执行的语句块的序列,由语句块名 按路径的执行顺序组成;分支组合是指路径所经历的分支的序列,由分支名按路 径的经历顺序组成;也就是说,语句组合记录路径执行的语句,分支组合记录路 径经历的分支。我们把路径的语句组合中的语句称为路径的执行语句,把路径的 分支组合中的分支称为路径的经历分支。另外,由于统计路径的需要,路径还分 为两类:正常和返回,类别为返回的路径经过了一个含有返回语句的语句块,因 此提前结束;类别为正常的路径在程序结束时结束。统计路径时,路径的缺省类 别为正常,当一条路径经过一个含有返回语句的语句块时,将该路径的类别设为 返回,该路径即结束。
步骤B具体包括:后序扫描所述结构对象,针对每一结构对象,将一个输入 路径集作为初始数据进行路径统计,顶层分支对象的输入路径集只含一条空路 径;针对语句块对象,在输入路径集的每条路径中记录该语句块名;针对分支对 象,在输入路径集的每条路径中记录该分支名,前一子对象的输出路径集作为下 一子对象的输入路径集;针对分支树对象,将输入路径集的拷贝作为每一子对象 的输入路径集。下面描述上述步骤中递归计算各结构对象时统计路径的详细步 骤:
图5是本实施例统计程序路径的流程示意图,其中,图5A是当对象为语句块 时统计路径的流程示意图,图5B是当对象为分支时统计路径的流程示意图,图 5C是当对象为分支树时统计路径的流程示意图。
图5A是当对象为语句块时统计路径的流程示意图。如图5A所示,步骤503 扫描路径集,即扫描输入路径集501,针对每一条路径,在步骤504判断它的类 别,如果类别为返回,则返回到步骤503处理下一条路径,否则在步骤505判断 该语句块对象的代码是否含有返回语句,如果是,则执行步骤506将路径的类别 设为返回再执行步骤507,否则直接执行步骤507,步骤507记录语句名,即在路 径的语句组合的最后添加该语句块名。所有路径处理完成后即得到输出路径集 502,输出路径集中的路径的数量与输入路径集一致。
图5B是当对象为分支时统计路径的流程示意图。当对象为分支时,依次计算 该对象的子对象,前一子对象计算后的输出路径集,作为下一子对象的输入路径 集,直到所有子对象计算完毕,最末子对象的输出路径集就是该分支对象的输出 路径集。如图5B所示,步骤511记录分支,即在输入路径集的每条路径的分支组 合的最后添加该分支名。步骤512扫描每一子对象,如果完毕或没有子对象则结 束,否则执行步骤513。步骤513判断该子对象是不是语句块,如果是则执行步骤 514,否则执行步骤515,步骤514递归执行图5A所示的计算,并将计算后的路 径集作为下一子对象的输入路径集;步骤515递归执行图5C所示的计算,并将输 出的路径集作为下一子对象的输入路径集。步骤514和步骤515执行后均返回到 步骤512处理下一子对象直到结束。
图5C是当对象为分支树时统计路径的流程示意图。如图5C所示,步骤523 剔除返回路径:将输入路径集521中类别为返回的路径拷贝到输出路径集522 中,并从输入路径集521删除。步骤524扫描子对象(分支),读取一个分支后, 步骤525将输入路径集拷贝一份作为该分支的输入路径集。步骤526针对该分支 递归执行图5B所示的计算,然后返回到步骤524处理下一分支。所有分支计算完 成后,步骤527将各分支的输出路径集汇总到整个分支树对象的输出路径集522 中,计算结束。
顶层分支对象的输入路径集只含一个空路径,所述空路径是指语句组合和分 支组合均为空的路径;顶层分支对象的输出路径集就是程序的路径集。路径集中 的每条路径,均记录了该路径所执行的语句块对象序列和该路径所经历的分支对 象序列。
当程序较复杂时,路径的数量会很庞大,要设计测试用例覆盖所有路径是不 现实的。可以将一些特定的代码所对应的对象隐藏,统计路径时,忽略隐藏的对 象及其直接或间接子对象,以便压缩路径的数量,例如,可以隐藏嵌套层次太深 的对象。
下面详细描述图1所示的步骤C,该步骤生成测试用例。本实施例用提示表 达式来描述测试用例,即用提示表达式来构成测试用例,属于不可执行的测试用 例,用户依据提示表达式确定具体的输入数据,编写测试代码,即可执行测试。 所述提示表达式用于描述测试用例的输入数据的范围或条件,包括:判定式、反 判定式及条件式、反条件式。
首先描述判定式和条件式,判定式就是判定表达式,即判定中用于决定是否 执行分支体的表达式,一个判定有一个判定式。条件式就是条件表达式,在一个 判定中,有一个或多个条件,各条件具有条件式。判定和条件都只有两个计算结 果:真或假。
我们用示例来进一步解释,如下面的判定:
IF A>0 AND B<0 THEN
A>0 AND B<0就是该判定的判定式,包含两个条件,条件1的条件式是:A >0;条件2的条件式是:B<0。
循环结构只关注是否会执行循环体一次,因此,循环结构的判定式是用于判 断循环体是否至少会执行一次的表达式。WHILE结构的判定式比较容易理解,例 如WHILE X>0 AND Y>0 DO…,判定式是X>0 AND Y>0,FOR结构比较复杂, 有些FOR结构为了语法简洁,判定式常与其他表达式如初始化表达式、递增表达 式混合,如C++的FOR结构:for(inti=0;i<10;i++)…,判定式是i<10;再如 BASIC的FOR结构:FOR I=0 TO 10 THEN…,其判定式是I<=10,再如BASIC 的FOR EACH Items DO…NEXT更特殊,判断循环体是否至少会执行一次的是 Items中集合项是否不为空,因此可列出这样的判定式:Items.Count>0,由于本 实施例生成的测试用例是不可执行的,只是一种提示信息,用户能理解并确定输 入数据就行,因此,即使Items没有Count属性,这种判定式也是可行的。
反判定式就是判定式取反的结果,反条件式就是条件式取反的结果。取反就 是将表达式中的等于操作符、关系操作符、逻辑操作符用相反的操作符替换,空 表达式取反后仍为空,所述相反的操作符如:等于和不等于互为相反,大于和小 于等于互为相反,小于和大于等于互为相反,逻辑与和逻辑或互为相反,逻辑非 的相反操作符一般是省略的即空的。例如:
上述判定IF A>0 AND B<0 THEN的反判定式是:A<=0 OR B>=0
条件1的反条件式是:A<=0
条件2的反条件式是:B>=0
再如,C++的判定if(C)…,其判定式是:C,反判定式是:!C,条件式是: C,反条件式是:!C。
本实施例在步骤A将程序代码映射为结构对象,由分支对象描述和处理判 定,因此,我们把判定式、条件、条件式、反判定式、反条件式称为分支的判定 式、条件、条件式、反判定式、反条件式。判定的取假分支也对应于一个分支对 象,其判定式、条件、条件式、反判定式、反条件式均为空。例如,对于判定: IF A>0 AND B<0THEN,如果没有ELSE IF分支,无论是否具有ELSE分支,均 可对应于两个分支对象:分支a和分支b,分支b的判定式、条件、条件式、反判 定式、反条件式均为空;分支a的判定式为:A>0 AND B<0,反判定式为:A<=0 OR B>=0;分支a具有两个条件,条件1的条件式是:A>0,反条件式是:A<= 0,条件2的条件式是:B<0,反条件式是:B>=0。
判定有两种计算结果:真和假,判定覆盖就是要覆盖每个判定的真和假两种 可能的计算结果,由于取假分支也对应于一个分支对象,因此,判定覆盖就是覆 盖所有分支对象。
条件式覆盖就是覆盖各分支的每个条件式,对于上述分支a来说,就是条件1 和条件2均至少计算一次,不考虑条件的计算结果。
每个条件有两种取值:真和假,我们用T来表示取真,用F来表示取假,并 加一个下标表示条件的序号,如分支a的条件1的取值表示为:T1、F1,条件2的 取值表示为:T2、F2。条件值覆盖就是要覆盖各分支的所有条件的所有取值,对于 分支a来说,就是要覆盖条件值T1、F1、T2、F2。
条件的取值有多种可能组合,上述分支a的条件值组合有:T1T2、T1F2、F1T2 、F1F2,我们把分支a称为这些条件值组合的所在分支。列出条件值组合的方法 属于现有技术,例如用多层循环可以得到分支的全部条件值组合,在此不作详 述。一个条件值组合实际上包括两方面信息:分支的各个条件和每个条件的取 值,例如,分支a的条件值组合之一T1F2,是指条件1取值为真,条件2取值为 假。在条件值组合中,有些条件是不可达的,本实施例将不可达的条件屏蔽。不 可达条件就是程序执行时不计算的条件或者即使计算也没有意义的条件,例如, 分支a的判定式A>0 AND B<0,如果条件1的值为假,则条件2是不计算的,因 此,当条件1为假时,条件2是不可达的,我们用字母S来替换条件值组合中不 可达的条件的取值,那么,分支a的四个条件值组合:T1T2、T1F2、F1T2、F1F2应 改为:T1T2、T1F2、F1S、F1S。屏蔽不可达条件可能会造成某些条件值组合重复, 例如分支a的条件值组合中,屏蔽不可达条件造成后两个条件值组合重复,我们 把最后一个条件值组合删除,得到分支a的有效条件值组合:T1T2、T1F2、F1S。 可用数理逻辑算法判断条件值组合中的不可达条件,属于现有技术,在此不作详 述。条件值组合覆盖就是要覆盖各分支的所有有效条件值组合,对于分支a来 说,就是要覆盖它的三种条件值组合:T1T2、T1F2、F1S,其中,不可达的条件是 可忽略的,分支a实际上要覆盖的是:T1T2、T1F2、F1。后文所说的某一分支的条 件值组合,均是指该分支的有效条件值组合。
下面进一步详细描述本实施例计算各种分支对象的判定式的步骤:
空分支或ELSE分支或DEFAULT分支或顶层分支的判定式为空。
DO…WHILE结构的两个分支的判定式均为空。由于DO…WHILE结构的两 个分支中,第一个分支肯定会执行一次,第二个分支肯定是不可达的,它们的判 定式在设计测试用例时可忽略,因此把它们的判定式视为空。
CASE分支用SWITCH表达式与常量表达式组成等式作为判定式,例如C++ 的SWITCH结构:switch(X){case 0…case 1…case N…},可组合出各分支的判定式 为:X==0/X==1/…/X==N。
FOR分支用条件表达式作为判定式,多个条件表达式用逻辑与连接,并可用 条件变量的初始值代替该条件变量。例如,C++的FOR结构:for(int i=0;i<10;i+ +)…,条件表达式为i<10,条件变量为i,其初始值为0,可用条件变量的初始值 代替该变量,因此,判定式为:0<10。再如Basic的FOR结构FOR I=0 TO 10 THEN…,其中I=0 TO 10等价于C++的i=0;i<=10,可以得到判定式为0<=10。 如果具有多个条件表达式则用逻辑与连接,如C++的FOR结构for(int i=0,int j= 10;i<10,j>0;i++,j--)…,其判定式为:0<10 && 10>0。本实施例将循环结构视为具 有执行循环体和不执行循环体两个分支,循环的判定实际上只考虑第一次的计算 结果,因此,当条件变量可确定初始值时,可用其初始值代替该条件变量。用条 件变量的初始值代替该变量的好处是提高依据提示表达式确定测试输入数据时的 效率,例如:如果判定式为0<10,计算结果恒为真,确定测试输入数据时无须考 虑该表达式,如果判定式为0>=10,计算结果恒为假,含有该判定式的测试用例是 无效的。
其他分支用判定中的条件表达式作为判定式,如C++的分支判定if(a<0 && B>0),其判定式为a<0 && B>0,再如Basic的分支判定IF A<0 AND B>0 THEN 其判定式为:A<0 AND B>0。
不同的编程语言有不同的语法,但所有判定都是通过计算出判定值来控制程 序的执行路线,因此,所有分支都可以计算出判定式或列出可作为判定式的表达 式,当然,有些分支的判定式为空。计算出分支的判定式后,即可依据判定式推 出反判定式,条件式及反条件式,具体的计算过程属于现有技术,在此不作详 述。
本实施例为以下逻辑覆盖生成测试用例:语句覆盖、判定覆盖、条件式覆 盖、条件值覆盖、条件值组合覆盖、路径覆盖,即依据不同的逻辑覆盖生成可完 成该逻辑覆盖的一组测试用例,其中每个测试用例均由提示表达式组成。一般来 说,白盒测试只选择其中一两种逻辑覆盖,而不需要完成所有的逻辑覆盖。下面 详细描述生成各种逻辑覆盖的测试用例的具体步骤:
C1.生成路径覆盖测试用例,具体包括:针对步骤B所获得的路径集中的每 一路径,执行用于生成一条路径的覆盖测试用例的步骤。
用于生成一条路径的覆盖测试用例的步骤具体包括:针对所述路径的每一经 历分支,依次选择该经历分支的在前姐妹分支的反判定式,及该经历分支自身的 判定式。分支的姐妹分支,就是该分支的父对象的所有分支,即直接属于同一分 支树的所有分支,也就是直接属于同一个分支结构的所有分支,当然也包括该分 支自身,其中,排在该分支之前的分支称为该分支的在前姐妹分支。图6是生成 一条路径的覆盖测试用例的流程示意图,如图6所示,步骤601扫描路径的分支 组合,针对每一经历分支,步骤602扫描其姐妹分支,针对每一姐妹分支,在步 骤603根据分支名判断该姐妹分支是否是该经历分支自身,如是,则执行步骤 605,否则执行步骤604。步骤604选择该姐妹分支的反判定式,然后返回步骤 602处理下一姐妹分支;步骤605选择该经历分支自身的判定式,然后返回步骤 601处理下一个经历分支,直到所有经历分支均处理完毕。
C2.生成语句覆盖测试用例,具体包括:
筛选可覆盖全部语句的最小数量的目标路径。语句覆盖就是覆盖步骤A所获 得的结构对象中的所有语句块对象,一般来说,达到语句覆盖的测试用例组合有 多种,本实施例用最小数量的测试用例覆盖所有的语句。选择目标路径的具体步 骤如下:开始时所有语句均为未覆盖,选择一条语句组合中包含未覆盖语句数量 最多的路径作为目标路径,将该目标路径已包含的语句标为已覆盖,继续选择直 到所有语句已覆盖,就得到了可覆盖全部语句的最小数量的目标路径。
针对上述每一目标路径,执行步骤C1所述的用于生成一条路径的覆盖测试用 例的步骤生成测试用例。由于所选路径包含了所有语句,因此,覆盖这些路径的 测试用例,也就是语句覆盖的测试用例。
C3.生成判定覆盖测试用例,具体包括:
筛选可覆盖全部分支的最小数量的目标路径。判定覆盖又叫分支覆盖,就是 覆盖步骤A所获得的结构对象中的所有分支对象,一般来说,达到判定覆盖的测 试用例组合有多种,本实施例用最小数量的测试用例覆盖所有的分支。选择目标 路径的具体步骤如下:开始时所有分支均为未覆盖,选择一条分支组合中包含未 覆盖分支数量最多的路径,将该路径已包含的分支标为已覆盖,继续选择直到所 有分支已覆盖,就得到了可覆盖全部分支的最小数量的目标路径。
针对上述每一目标路径,执行步骤C1所述的用于生成一条路径的覆盖测试用 例的步骤生成测试用例。由于所选路径包含了所有分支,因此,覆盖这些路径的 测试用例,也就是判定覆盖的测试用例。
C4.生成条件值组合覆盖测试用例,具体包括:针对每一分支的每一条件值 组合,执行用于生成一个条件值组合的覆盖测试用例的步骤。
用于生成一个条件值组合的覆盖测试用例的步骤具体包括:选择一条经历该 条件值组合的路径作为目标路径;针对该目标路径的每一前导分支,依次选择该 前导分支的在前姐妹分支的反判定式,及该前导分支自身的判定式;针对该条件 值组合,依次选择取真值的条件的条件式,及取假值的条件的反条件式,忽略不 可达条件。经历该条件值组合的路径,是指经历该条件值组合所在分支的路径, 即分支组合含有该条件值组合所在分支的路径。所述前导分支,是指在目标路径 的分支组合中,位于该条件值组合所在分支之前的分支。本步骤分成两步:依据 目标路径生成测试用例的前半部分和依据条件值组合生成测试用例的后半部分。 第一步与步骤C1所述的用于生成一条路径的覆盖测试用例的步骤相似,唯一的区 别是,只针对前导分支选择提示表达式,忽略后续的分支,具体步骤不再重复。 下面详细描述第二步,图7是依据条件值组合生成测试用例的一部分的流程示意 图,如图7所示,步骤701扫描条件值组合,针对每一条件,步骤702判断是否 不可达,不可达条件就是在条件值组合中条件值标为S的条件,如是则返回步骤 701处理下一条件,否则执行步骤703,步骤703判断该条件的取值,如果取真值 则执行步骤705,否则执行步骤704。步骤704选择该条件的反条件式,步骤705 选择该条件的条件式。步骤704和705执行后均返回步骤701处理下一条件,直 到所有条件均处理完毕。
C5.生成条件式覆盖测试用例,具体包括:针对每一分支,执行下述步骤:
选择可覆盖该分支全部条件式的最小数量的目标条件值组合。选择目标条件 值组合的具体步骤如下:开始时该分支的所有条件均为未覆盖,在该分支的条件 值组合中选择一个可达的未覆盖条件数量最多的条件值组合,将该条件值组合中 可达的条件标为已覆盖,继续选择直到该分支所有条件已覆盖,就得到了可覆盖 该分支全部条件式的最小数量的目标条件值组合。例如,分支a的条件值组合 有:T1T2、T1F2、F1S,第一次扫描,选中T1F2,已将两个条件覆盖,因此目标条 件值组合就是T1F2。
针对每一目标条件值组合,执行步骤C4所述的用于生成一个条件值组合的覆 盖测试用例的步骤生成测试用例。由于所选条件值组合包含了所有条件,因此, 覆盖这些条件值组合的测试用例,也就是条件式覆盖的测试用例。
C6.生成条件值覆盖测试用例,具体包括:针对每一分支,执行下述步骤:
选择可覆盖该分支全部条件值的最小数量的目标条件值组合。选择目标条件 值组合的具体步骤如下:开始时该分支的所有条件值均为未覆盖,在该分支的条 件值组合中选择一个包含未覆盖条件值数量最多的条件值组合,将该条件值组合 已包含的条件值标为已覆盖,继续选择直到所有条件值已覆盖,就得到了可覆盖 该分支全部条件值的最小数量的目标条件值组合。例如,分支a的条件值组合 有:T1T2、T1F2、F1S,第一次扫描,选中T1T2,它覆盖两个条件值:T1、T2,再次 扫描,选中T1F2,它覆盖剩余的一个条件值:F2,再次扫描,选中F1S,它覆盖剩 余的一个条件值:F1,因此目标条件值组合就是T1T2、T1F2、F1S。
针对每一目标条件值组合,执行步骤C4所述的用于生成一个条件值组合的覆 盖测试用例的步骤生成测试用例。由于所选条件值组合包含了所有条件值,因 此,覆盖这些条件值组合的测试用例,也就是条件值覆盖的测试用例。
为了得到更简洁的测试用例,可以对测试用例进行化简,即删除或合并测试 用例中语义重复或矛盾的部分。化简一般以一组姐妹提示表达式为单位。依据路 径的一个经历分支及其在前姐妹分支生成的提示表达式,称为一组姐妹提示表达 式。示例一:C++的SWITCH结构:switch(X){case 0…case 1…case 2…},各分支 的判定式为:X==0/X==1/X==2,如果路径经历了第三分支,则依据该经历分支及 其在前姐妹分支生成的提示表达式为:X!=0/X!=1/X==2,显然,前两个提示表达 式是多余的;示例二:C++的IF结构,if(X>=1000)…else if(X>=100)…else if(X> 10)…else…,如果路径经历了第四分支,则依据该经历分支及其在前姐妹分支生成 的提示表达式为:X<1000/X<100/X<=10,显然,前两个提示表达式是多余的。可 以用字符串对比的方法进行粗略的化简:从后向前依次扫描各提示表达式,如果 某一变量或表达式是在后提示表达式中某一等式的左操作数,则删除在前提示表 达式中以该变量或表达式为左操作数的等式或不等式,所述等式是指用等于操作 符连接左操作数和右操作数的表达式,所述不等式是指用不等于操作符连接左操 作数和右操作数的表达式,如示例一;如果某一变量或表达式是在后提示表达式 中某一关系式的左操作数,则删除在前提示表达式中以该变量或表达式为左操作 数的同符号的关系式,所述关系式是指用关系操作符如大于、小于、大于等于、 小于等于连接左操作数和右操作数的表达式,所述同符号是指关系操作符相同, 小于和小于等于、大于和大于等于可以视为同符号,如示例二。使用词法分析和 语法分析技术解析提示表达式的语义,然后删除或合并多余的表达式,可以进行 精确的化简,具体实施步骤属于现有技术,在此不作详述。
上面详细描述了本发明的一个实施例,在该实施例中,使用提示表达式描述 测试用例,测试用例不能直接执行,用户依据提示表达式确定具体的测试输入数 据,编写可执行的测试代码,才能执行测试。后面描述的本发明的另一个实施 例,是在已有可执行的测试用例的基础上,为了达到某一逻辑覆盖,设计新的测 试用例。由于已有可执行的测试用例,该实施例从已有的测试用例中,选择逻辑 目标的近似测试用例,并用提示表达式描述修改提示,用户依据修改提示修改近 似测试用例,即可得到用于覆盖预期逻辑目标的测试用例。
图8是本发明另一个实施例的总体流程图。如图8所示,步骤A、B与第一 实施例相同,步骤D对程序进行插装,步骤E编译并运行插装后的程序,步骤F 记录逻辑覆盖信息,步骤G计算逻辑目标的近似测试用例,步骤H生成修改提 示。
如图8所示,步骤D对程序进行插装。插装是软件测试领域常用的技术,就 是在被测试程序中插入代码,插装技术是现有技术,在此不对具体实施细节作详 细描述,但不同的插装目的具有不同的插装函数和插装位置,下面详细描述本实 施例的插装函数和插装位置。
插装函数就是插装代码调用的函数。本实施例插装的目的是监视语句或条件 的执行状况,采用两个插装函数:语句监视函数和条件监视函数,语句监视函数 用于监视语句的执行,在本实施例,语句监视函数在语句执行时传递语句的标识 即语句块名,条件监视函数用于监视条件的计算或计算结果,在本实施例,条件 监视函数在条件被计算时传递条件的值。我们把语句监视函数称为函数A,把条 件监视函数称为函数B。本实施例可以为各种逻辑覆盖目标设计测试用例,对于语 句覆盖、判定覆盖和路径覆盖,可以只使用函数A进行插装,对于条件式覆盖、 条件值覆盖、条件值组合覆盖,则还应使用函数B进行插装。
函数A原形如下(伪代码):
VOID函数A(语句块名)
函数A可以没有返回值,只有一个参数:语句块名,用于识别所监视的语句 块。插装时在各语句块对象对应的代码前面插入函数A的调用代码,该语句块名 作为实参。
函数B原形如下(伪代码):
BOOL函数B(分支名,条件编号,条件值)
函数B返回一个布尔值,该返回值恒为真(TRUE)。三个参数:分支名,用于 识别各分支;条件编号,用于识别一个分支里的各个条件;条件值,也是一个布 尔值,有真和假两个取值。插装时,在各条件的前后两端分别插入函数B的调用 代码,前端调用时,条件值实参为假,后端调用时,条件值实参为真;另外两个 参数在前后端调用时一致,分支对象名作为第一个实参,分支中条件的编号作为 第二个实参。调用函数B的代码和条件表达式用逻辑与相连,最好用括号把三者 括起来。由于函数B总是返回一个真值,不会干扰判定及判定中各条件的计算过 程和计算结果。
下面是插装的一个示例(伪代码,带下划线的为调用插装函数的代码):
插装前:
IF A>0 AND B<=0 THEN
语句块
END IF
插装后:
IF( 函数B(分支名,1,假)AND A>0 AND 函数B(分支名,1,真))AND
( 函数B(分支名,2,假)AND B<=0 AND 函数B(分支名,2,真))THEN
函数A(语句块名)
语句块
END IF
函数A运行时传递语句名,函数B运行时传递分支名、条件编号、条件值, 因此,它们要实现的功能就是将这些信息发送给记录逻辑覆盖信息的步骤。如果 记录逻辑覆盖信息的步骤属于另一个应用程序,传递数据时可以使用进程间数据 交换技术,实现的途径有多种,如共享内存、网络、命名管道,也可以将数据保 存到文件,由记录逻辑覆盖信息的步骤主动读取,具体实现细节属于现有技术, 在此不作详述。
如图8所示,步骤E编译并运行插装后的程序。为了运行被测试程序,需要 有驱动程序,驱动程序设定输入数据,并调用被测试程序,使被测试程序得于执 行。由于本实施例已有可执行测试用例,测试用例就构成了驱动程序,一般来 说,一个测试用例运行被测试程序一次。例如下面的被测试代码(编程语言为C+ +,同样的方式适用于其他编程语言):
int CMyClass∷Add(int x,int y)
{
      return x+y;
}
可以用下面的驱动代码来运行:
CMyClass obj1;
obj1.Add(0,0);
CMyClass obj2;
obj2.Add(1,1);
包括两个测试用例,使用不同的输入数据,分别驱动被测试程序执行一次。 为了便于识别不同的测试用例,还可以在每个测试用例开始前向记录逻辑覆盖信 息的步骤发送一个消息。
本实施例使用用户提供的编译器编译插装后的被测试程序及其驱动程序,得 到可执行文件,运行可执行文件,即可运行被测试程序。
如图8所示,步骤F记录逻辑覆盖信息。被测试程序运行的时候,插装代码 传递逻辑覆盖信息,步骤F记录这些信息,具体包括:
记录语句覆盖信息:当一个语句块被执行时,函数A传递该语句块名,本实 施例以一个测试用例所执行的语句块作为一组,记录语句块执行状况,称为语句 覆盖记录,我们把一个测试用例所覆盖的语句块称为该测试用例的语句组合。
统计已覆盖路径及已覆盖路径的覆盖用例:被测试程序运行结束后,将路径 的语句组合与各测试用例的语句组合进行比较,如果路径的语句组合是测试用例 的语句组合的子集,则该路径已被该测试用例覆盖,称为已覆盖路径,该测试用 例称为该路径的覆盖用例。由于路径统计时不考虑循环的次数,当循环结构里含 有分支时,一个测试用例可能会覆盖多条路径,也就是说,一个测试用例可能是 多条路径的覆盖用例。
如果插装时使用了函数B,还应记录条件覆盖信息。函数B传递的是条件执 行时的条件值,针对每一条件,本实施例用集合(如数组或链表)来记录该条件在 各个测试用例的执行结果,称为条件覆盖记录,每个测试用例占用一个集合项, 各集合项的初始值为未覆盖,运行测试时,如果条件前端的函数B执行了而后端 的函数B未执行,则记录的是前端函数B的条件值(假),如果两者都执行了,则 用后端函数的条件值(真)改写记录值。对于一个分支,一个测试用例所记录的条 件值的组合,称为该分支在该测试用例的条件值组合,或该测试用例的该分支的 条件值组合。
如图8所示,步骤G计算逻辑目标的近似测试用例。逻辑目标就是所设计的 测试用例意图覆盖的某种逻辑单位。例如,语句块、分支、路径、条件式、条件 值、条件值组合,都可以作为逻辑目标,一般来说,逻辑目标是未覆盖的逻辑单 位。分支是判定覆盖的逻辑目标。步骤G从已有的测试用例中选择一个近似测试 用例,因此,近似测试用例是一个已有测试用例,该测试用例作最小修改即可覆 盖所述逻辑目标,最小修改是指需修改的数据尽可能少。例如,一个被测试程序 有三个参数,已有两个测试用例,逻辑目标是一个语句块,为了覆盖该语句块, 测试用例1需要修改两个参数,测试用例2需要修改一个参数,则测试用例2就 是该逻辑目标的近似测试用例。不同的逻辑目标用不同的步骤计算近似测试用 例,分别详细描述如下:
G1.计算目标路径的近似测试用例:
逻辑目标是路径,我们把该路径称为目标路径,执行用于计算目标路径的近 似路径的步骤计算该目标路径的近似路径;目标路径的近似测试用例等于该目标 路径的近似路径的覆盖用例。
用于计算目标路径的近似路径的步骤具体包括:比较目标路径与各已覆盖路 径的分支组合,重叠分支最多的已覆盖路径,就是目标路径的近似路径。重叠分 支是从头开始的连续的相同分支。多条已覆盖路径重叠分支相同时,比较首个非 重叠分支,首个非重叠分支在后优先和最接近优先,具体来说,比较首个非重叠 分支,如果既有在后的候选路径又有在前的候选路径,则选择在后的候选路径; 如果有多条在后的候选路径,则选择最前的;如果有多条在前的候选路径,则选 择最后的,所述“在前”、“在后”,是指候选路径的首个非重叠分支与目标路径的 首个非重叠分支相比较而言,所述“最前”、“最后”,是指候选路径的首个非重叠 分支相比较而言,由于本实施例的分支名是自动递增的,并且所有首个非重叠分 支均属于同一个分支树对象,比较分支名即可判别“在前”、“在后”与“最前”、 “最后”。我们把目标路径的第一个非重叠分支称为阻塞分支,把近似路径的第一 个非重叠分支称为临界分支。
G2.计算目标分支的近似测试用例:
逻辑目标是分支,我们把该分支称为目标分支,用下述步骤计算其近似测试 用例:
选择所有经历目标分支的路径作为候选目标路径,即选择分支组合中包含目 标分支的路径作为候选目标路径。
计算各候选目标路径的近似路径:针对每一候选目标路径,执行步骤G1所述 的用于计算目标路径的近似路径的步骤计算其近似路径;
选择临界差最小的候选目标路径作为目标路径:计算各候选目标路径的临界 差,临界差最小的候选目标路径为该目标分支的目标路径。临界差就是候选目标 路径中目标分支的偏移与该候选目标路径的近似路径的临界分支的偏移的差,分 支的偏移是指在一条路径中,该分支之前的分支的条数。例如:候选目标路径的 分支组合为:abdfh,目标分支为f,其近似路径的分支组合为abekj,则候选目标 路径中目标分支的偏移是3,近似路径的临界分支是e(第一个非重叠分支),其偏 移是2,临界差为1。
目标分支的近似测试用例等于目标路径的近似路径的覆盖用例。
G3.计算目标语句的近似测试用例:
逻辑目标是语句块,我们把该语句块称为目标语句,目标语句的近似测试用 例等于该目标语句所在分支的近似测试用例。我们把目标语句所在的分支(即该语 句块的父对象)称为目标分支,执行步骤G2计算目标分支的目标路径、近似路 径、和近似测试用例,该目标分支的目标路径、近似路径、和近似测试用例就是 目标语句的目标路径、近似路径、和近似测试用例。
G4.计算目标条件值组合的近似测试用例:
逻辑目标是条件值组合,我们把该条件值组合称为目标条件值组合,执行用 于计算目标条件值组合的近似测试用例的步骤计算该目标条件值组合的近似测试 用例。
用于计算目标条件值组合的近似测试用例的步骤具体包括:
选择所有覆盖了目标分支的测试用例作为候选测试用例。目标分支是指目标 条件值组合所在的分支。依据条件覆盖记录,如果一个测试用例的目标分支的条 件值组合中,至少有一个条件的值为真或假,则该测试用例覆盖了目标分支。在 完成了语句覆盖的基础上,符合条件的候选测试用例一定存在,如果不存在,应 先完成语句覆盖。
选择相符条件值最多的候选测试用例作为目标条件值组合的近似测试用例。 具体来说,针对每一候选测试用例,对比目标分支的该测试用例的条件值组合与 目标条件值组合,相符条件值最多的候选测试用例为目标条件值组合的近似测试 用例。
G5.计算目标条件式的近似测试用例:
逻辑目标是条件式,我们把该条件式称为目标条件式,把目标条件式所在的 分支称为目标分支,用下述步骤计算该目标条件式的近似测试用例:
选择所有目标条件式可达的条件值组合作为候选目标条件值组合:在目标分 支的条件值组合中选出目标条件式可达的条件值组合,即目标条件式所对应的条 件未被屏蔽的条件值组合作为候选目标条件值组合。
计算各候选目标条件值组合的近似测试用例:针对各候选目标条件值组合, 执行步骤G4所述的用于计算目标条件值组合的近似测试用例的步骤计算该候选目 标条件值组合的近似测试用例。
选择已覆盖的在前条件式最多的候选条件值组合作为目标条件值组合:计算 各候选目标条件值组合的近似测试用例所覆盖的目标分支的在前条件的个数,最 多者为目标条件值组合。在前条件个数就是在候选目标条件值组合中,目标条件 式之前的条件的个数,不包括不可达条件;测试用例所覆盖的条件,是指目标分 支在该测试用例的条件值组合中,条件值为真或为假的条件。
目标条件式的近似测试用例等于目标条件值组合的近似测试用例。
G6.计算目标条件值的近似测试用例:
逻辑目标是条件值,我们把该条件值称为目标条件值,把目标条件值所在的 分支称为目标分支,用下述步骤计算该目标条件值的近似测试用例:
选择所有包含目标条件值的条件值组合作为候选目标条件值组合:在目标分 支的条件值组合中选出包含目标条件值的条件值组合,作为候选目标条件值组 合。
计算各候选目标条件值组合的近似测试用例:针对各候选目标条件值组合, 执行步骤G4所述的用于计算目标条件值组合的近似测试用例的步骤计算该候选目 标条件值组合的近似测试用例。
选择已覆盖的在前条件值最多的候选目标条件值组合作为目标条件值组合: 计算各候选目标条件值组合中已被近似测试用例所覆盖的在前条件值的个数,最 多者为目标条件值组合。在前条件值就是在候选目标条件值组合中,目标条件值 之前的条件值,不包括不可达条件;已被近似测试用例所覆盖的条件值,是指该 条件值与近似测试用例的目标分支的条件值组合中相应条件值相符的条件值。
目标条件值的近似测试用例等于目标条件值组合的近似测试用例。
如图8所示,步骤H生成修改提示。修改提示用于指导对逻辑目标的近似测 试用例进行修改,使修改后的测试用例可以覆盖该逻辑目标。修改提示由提示表 达式构成,并分为两类:已满足条件和待满足条件,待满足条件是近似测试用例 未满足的条件,依据待满足条件修改近似测试用例即可获得用以覆盖预期的逻辑 目标的测试用例;已满足条件指出近似测试用例已满足的,并且修改后的测试用 例仍然应满足的条件。待满足条件是修改提示的核心,已满足条件只是一种参 考,并不是必需的。
如果逻辑目标是路径、语句块或分支,用下述步骤生成修改提示:
H1.针对目标路径的每一经历分支,依次选择该经历分支的在前姐妹分支的 反判定式,及该经历分支自身的判定式。阻塞前或临界前属已满足条件,其他属 待满足条件;已满足条件可忽略。目标路径是逻辑目标的目标路径,阻塞前是 指:目标路径的阻塞分支之前,不包括阻塞分支,临界前是指:目标路径的近似 路径的临界分支之前,包括临界分支,也就是说,据以选择提示表达式的分支中 (包括目标路径的经历分支及经历分支的在前姐妹分支),如果出现了阻塞分支, 从该阻塞分支开始,所选择的提示表达式就是待满足条件,或者,如果出现了目 标路径的近似路径的临界分支,从该临界分支的下一分支开始,所选择的提示表 达式就是待满足条件。目标路径、近似路径、阻塞分支与临界分支,在步骤G1、 G2、G3中已作详细描述。由于已满足条件只是一种参考信息,因此,生成修改提 示时可以忽略已满足条件。
上述步骤生成的已满足条件由判定式或反判定式组成,如果分支的判定含有 多个条件,那么已满足条件可能不够明确,影响修改提示的精确性。例如如下修 改提示(C++语法):
已满足条件:a>0||b<0
待满足条件:a==0||x==1
仅从待满足条件看,把a的值改为0或把x的值改为1都可以得到新的测试 用例,但已满足条件实际上有两种可能:a>0或b<0,如果a>0,那么把a的值改 为0就破坏了已满足条件,新的测试用例将不能覆盖预期逻辑目标。为了得到更 精确的修改提示,可以使用改进后的步骤H1,具体包括:
针对目标路径的每一经历分支,依次选择该经历分支的在前姐妹分支及该经 历分支自身的提示表达式,其中,阻塞前或临界前的分支按下述步骤选择提示表 达式:依据该分支在近似测试用例的条件值组合,选择取真值的条件的条件式, 取假值的条件的反条件式,忽略不可达条件;其他分支按下述步骤选择提示表达 式:在前姐妹分支选择反判定式,经历分支自身选择判定式。阻塞前或临界前属 已满足条件,否则属待满足条件;已满足条件可忽略。近似测试用例是指逻辑目 标的近似测试用例。使用改进后的步骤H1生成的上述修改提示,有两种可能结 果:
已满足条件:a>0
待满足条件:a==0||x==1
在这种情况下,只能把x的值改为1来得到符合预期的测试用例;
已满足条件:b<0
待满足条件:a==0‖x==1
在这种情况下,把a的值改为0或把x的值改为1都可以得到符合预期的测 试用例。
根据上述步骤(包括改进前和改进后的步骤)生成的修改提示对近似测试用例 进行修改,可得到可以覆盖预期逻辑目标的测试用例,但这种修改提示比较复 杂,待满足条件可能较多,修改测试用例的工作量有时较大,为了克服这些缺 点,上述步骤可以进一步包括:忽略阻塞分支之后的分支。也就是说,上述步骤 在选择了阻塞分支的判定式后即结束,忽略后面的分支。这样,待满足条件很 少,修改测试用例的工作量很小,通常只需修改一个数据,但该测试用例覆盖的 可能不是预期的逻辑目标,例如,当逻辑目标是一条路径时,实际覆盖的可能是 另一条经过阻塞分支的路径,但也达到了提高路径覆盖率的目的,同时,逻辑目 标可以随便选择,每次用最小的工作量提高逻辑覆盖率,具有很高的效率。
如果逻辑目标是条件值组合、条件式或条件值,用下述步骤生成修改提示:
H2.选择一条经历目标分支的已覆盖路径作为目标路径,针对该目标路径的 每一前导分支,依次选择该前导分支的在前姐妹分支的反判定式,及该前导分支 自身的判定式;针对目标条件值组合,依次选择取真值的条件的条件式,取假值 的条件的反条件式,忽略不可达条件。目标分支是指逻辑目标所在的分支,也就 是目标条件值组合所在的分支,目标条件值组合在步骤G4、G5、G6中已作详细 描述。选择一条经历目标分支的已覆盖路径作为目标路径,是指从已覆盖路径中 选择一条分支组合包含了目标分支的路径作为目标路径,如果已完成语句覆盖, 目标路径一定存在。
与步骤H1类似,为了得到更精确的修改提示,可以使用改进的步骤H2,具 体包括:
选择一条经历目标分支的已覆盖路径作为目标路径,针对该目标路径的每一 前导分支,依次选择该前导分支的在前姐妹分支及该前导分支自身在近似测试用 例的条件值组合中取真值的条件的条件式,取假值的条件的反条件式,忽略不可 达条件;针对目标条件值组合,依次选择取真值的条件的条件式,取假值的条件 的反条件式,忽略不可达条件。
上述步骤(包括改进前和改进后的步骤)还可以进一步包括:忽略目标条件及 目标条件后的条件。目标条件是指:对于条件值组合覆盖,无目标条件,对于条 件式覆盖,目标条件式对应的条件为目标条件,对于条件值覆盖,目标条件值对 应的条件为目标条件。对于条件式覆盖和条件值覆盖来说,目标条件式或目标条 件值对应的条件及其后的条件的取值对于是否覆盖该条件式或条件值无影响,因 此选择提示表达式时可以忽略这些条件。
上述步骤生成的修改提示中,针对目标路径选择的提示表达式属已满足条 件;针对目标条件值组合选择的提示表达式,条件值已被近似测试用例所覆盖的条 件对应的提示表达式属已满足条件,其他属待满足条件。已被近似测试用例所覆 盖的条件值,是指该条件值与近似测试用例的目标条件值组合所在分支的条件值组 合中相应条件值相符的条件值。已满足条件可忽略。
为了得到更简洁的修改提示,可以对修改提示进行化简,即删除或合并修改 提示中语义重复或矛盾的部分,第一实施例的步骤C对测试用例的化简作了详细 描述,本实施例的修改提示与第一实施例的测试用例都是由提示表达式构成的, 因此,对修改提示进行化简的详细步骤,与第一实施例所述的对测试用例化简的 步骤相同。
修改提示由提示表达式构成,在多数情况下,依据修改提示可以确定新的测 试数据,但修改提示并未描述代码间的依赖关系,例如下面的伪代码: 函数名(X)
X=X+1
IF X<1 THEN
目标语句
END IF
函数结束
为了覆盖目标语句,修改提示包括提示表达式:X<1,根据该提示表达式, 参数X可以取值为0,显然,由于代码间的依赖关系,X为0并不能覆盖目标语 句。为了反映代码间的依赖关系,修改提示还可以包括提示代码,所述提示代码 就是目标路径所执行的代码,目标路径是指步骤H1或H2所述的目标路径。如前 所述,路径具有语句组合,语句组合就是路径所执行的语句块对象序列,语句块 对象保存了相应的代码,路径的语句组合所对应的代码就是路径的执行代码。一 般来说,提示代码只需包括目标路径的前导代码,如果逻辑目标是语句、分支或 路径,前导代码是指阻塞分支之前的代码,如果逻辑目标是条件式、条件值或条 件值组合,前导代码是目标分支之前的代码,目标分支就是逻辑目标所在的分 支。判断前导代码的方法是:扫描目标路径的语句组合,针对每一语句块对象, 如果它的直接或间接父分支有一个是阻塞分支或目标分支,则该语句块对象就是 前导代码的终结点,即前导代码是指路径的语句组合中该语句块对象之前的语句 块对象所对应的代码。语句块对象的直接或间接父分支,是指该语句块对象的直 接或间接父对象中的分支对象。
在步骤G之前,还可以增加步骤I,该步骤统计逻辑覆盖,即针对某种逻辑覆 盖,统计其已覆盖部分和未覆盖部分。步骤I所获得的统计结果,可用以显示已有 测试的逻辑覆盖率,也可以列出未覆盖的逻辑目标供用户选择。
步骤I具体包括:
I1统计路径覆盖,即统计已覆盖路径和未覆盖路径,具体步骤已在步骤F中 描述,不再重复。
I2.统计语句覆盖,语句覆盖就是覆盖步骤A所获得的所有语句块对象,语句 覆盖记录中所记录的语句均为已覆盖语句,其他为未覆盖语句。
I3.统计分支覆盖,已覆盖的路径所经历的分支,就是已覆盖分支,即已覆盖 路径的分支组合中的所有分支都是已覆盖分支,所有已覆盖路径均未经历的分支 为未覆盖分支。
I4.统计条件式覆盖,依据条件覆盖记录,如果该条件的各测试用例的值均为 未覆盖,则该条件式未覆盖,否则该条件式已覆盖。
I5.统计条件值覆盖,依据条件覆盖记录,如果该条件在各测试用例的值至少 有一个为真,则该条件的取真值已覆盖,否则未覆盖;用同样的方法统计条件的 取假值。
I6.统计条件值组合覆盖,依据条件覆盖记录,各测试用例的条件值组合为已 覆盖条件值组合,条件覆盖记录中未记录的条件值组合为未覆盖。
图9是本发明再一个实施例的总体构成示意图。如图9所示,本实施例是一 个测试用例设计系统,包括:用于将程序代码映射为结构对象的装置901,用于统 计程序路径的装置902,用于对程序进行插装的装置903,用于记录逻辑覆盖信息 的装置904,用于统计逻辑覆盖的装置905,用于计算逻辑目标的近似测试用例的 装置906,用于生成修改提示的装置907,其中,装置903是可选的,该装置自动 对程序进行插装,如果省略该装置,可以用人工对程序进行插装;装置905和装 置907也是可选的。
使用本实施例示出的测试用例设计系统进行测试用例设计的步骤如下:
使用装置901将程序代码映射为结构对象;
使用装置902统计程序路径;
使用装置903对程序进行插装;
使用用户提供的编译器编译插装后的程序,得到可执行文件,运行可执行文 件。
使用装置904记录逻辑覆盖信息;
使用装置905统计逻辑覆盖;
使用装置906计算逻辑目标的近似测试用例;
使用装置907生成修改提示。
本实施例依据前述实施例中步骤A所描述的方法实现装置901;步骤B所描 述的方法实现装置902;步骤D所描述的方法实现装置903;步骤F所描述的方法 实现装置904;步骤I所描述的方法实现装置905;步骤G所描述的方法实现装置 906;步骤H所描述的方法实现装置907,在此不作重复。
以上实施例仅是本发明的较佳实施方式,仅用以说明发本明而非限制,对本 发明进行修改、变形或者等同替换而不脱离本发明的精神和范围,均应涵盖于本
发明的范围之内。
高效检索全球专利

专利汇是专利免费检索,专利查询,专利分析-国家发明专利查询检索分析平台,是提供专利分析,专利查询,专利检索等数据服务功能的知识产权数据服务商。

我们的产品包含105个国家的1.26亿组数据,免费查、免费专利分析。

申请试用

分析报告

专利汇分析报告产品可以对行业情报数据进行梳理分析,涉及维度包括行业专利基本状况分析、地域分析、技术分析、发明人分析、申请人分析、专利权人分析、失效分析、核心专利分析、法律分析、研发重点分析、企业专利处境分析、技术处境分析、专利寿命分析、企业定位分析、引证分析等超过60个分析角度,系统通过AI智能系统对图表进行解读,只需1分钟,一键生成行业专利分析报告。

申请试用

QQ群二维码
意见反馈