一种残膜回收机防缠绕挑膜装置的制 一种秧草收获机用电力驱动行走机构

基于结构化程序自动合成的代码覆盖率工具测试的方法

2022-07-23 13:05:17 来源:中国专利 TAG:


1.本发明涉及软件测试技术领域,特别是涉及一种基于结构化程序自动合成的代码覆盖率工具测试的方法。


背景技术:

2.代码覆盖率是软件测试中的一种度量,用于描述程序中源代码被测试的比例和程度,从覆盖源程序语句的详尽程度分析。
3.代码覆盖率被广泛应用于许多软件测试技术当中,例如基于覆盖率的回归测试、编译器测试、调试优化等等。通过分析覆盖率报告中未覆盖的代码,可以反推前期测试设计是否充分,没有覆盖到的地方是否是设计的盲点等等,后续可补充测试用例设计;如果检测出程序中的无用代码,可以反推代码设计中的不合理之处。可以看出,代码覆盖率不论在科研还是实际生产中都具有重要的作用,因此,代码覆盖率工具的正确性十分关键。
4.目前聚焦于覆盖率工具正确性测试的工作较少,对现有工作调研后发现,代码覆盖率工具正确性测试方法主要有差分测试和蜕变测试两种。上述两种方法的测试用例都来自于csmith和现有编译器测试套件,这些测试程序结构复杂且不利于调试,后续人工分析工作量巨大;并且目前工作都集中于c语言的覆盖率工具,方法通用性较差,无法快速适用于不同语言。另外若要保证测试方法的通用性,则需要解决测试oracle问题,即如何判断一个覆盖率工具给出的报告是正确的。


技术实现要素:

5.目前针对代码覆盖率的工具较少,且多数存在结构复杂、不利调试、通用性差、无法快速适用不同语言和后续人工分析工作量巨大等问题,为解决上述问题,本发明通过以下技术方案来实现。
6.一种基于结构化程序自动合成的代码覆盖率工具测试方法,其特征在于,包括如下步骤:
7.步骤1):输入自动合成的结构化程序包含的控制流结构数量n,利用枚举算法重复排列生成多个控制流结构序列,其中一个结构序列表示为ss[n 1]={s0,s1,...,sn},其中s0为main函数结构,其余s1~sn为控制流结构;
[0008]
步骤2):根据控制流自身性质以及在结构序列中的位置,为序列中的每个结构s
index
初始化可插入点位置数组ps
index
[],每个位置数组内部元素为若干可插入点位置二元组pair;
[0009]
步骤3):以步骤1)获得的结构序列和步骤2)获得的每个结构对应的位置数组作为输入,搭建由main函数和控制流结构组成的程序框架,搭建过程中使用枚举加去重算法的方式,为每个控制流结构s
index
(1≤index≤n)从位置数组ps
index-1
[]中选择一个合理的pair作为控制流结构插入点,当所有s
index
(1≤index≤n)都确定了对应插入位置,程序框架搭建完成;
[0010]
步骤4):依照语法规则约束,为每个控制流结构随机选择合理的表达式作为条件判断语句,并向程序框架中随机插入若干表达式语句、赋值语句、跳转语句等丰富生成程序的语义信息;
[0011]
步骤5):步骤4)中不同条件判断语句、表达式语句或赋值语句可能用到同一变量,故引入声明语句去重算法,为每个变量选择在当前程序中声明位置的下界,并在位置信息上界到当前下界中随机选择一位置信息插入声明语句,保证生成程序可正确编译;
[0012]
步骤6):分析步骤5)中确定的控制流结构、判断语句和跳转语句,消除显式死循环;
[0013]
步骤7):向内部无任何结构语句的控制流结构,添加空语句,搭建完整结构化程序,并对应程序合成测试程序源代码;
[0014]
步骤8):对步骤7)中生成的结构化进行执行情况预测,按照明确执行、明确不执行和不明确执行情况对控制流结构和语句打标,结合程序结构化信息和执行情况打标结果,生成不变式;
[0015]
步骤9):调用编译器覆盖率工具,生成步骤7)中测试程序源代码对应的覆盖率报告,利用不变式规则对覆盖率报告进行正确性测试,如果报告不满足不变式,认为覆盖率工具可能存在错误。
[0016]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所述步骤1)中利用枚举算法进行重复排列的控制流结构为常见选择结构if/if-else和循环结构for/while/do-while共5种,在输入控制流数量为n时,算法会生成5n个控制流结构序列,所有序列的第一个元素都是main。
[0017]
上述基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所述步骤2)中结构序列中有一个main函数结构和n个控制流结构,每个结构对应一个可插入点位置数组ps[],一个结构序列合计有n 1个可插入点位置数组ps0~psn;所有可插入点位置数组中的元素均若干为二元组pair,pair形为《index,position》,其中index表示结构序列中的索引,position表示结构内部代码块索引。
[0018]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所述步骤3)每个控制流结构s
index
(1≤index≤n),从位置数组ps
index-1
[]中选择一个合理的pair作为控制流结构插入点时,需要遵守一种约束关系,从而保证生成合成的程序框架是唯一的。
[0019]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,使用一种去重算法描述约束关系,去重算法规定两个控制流结构si和sj(i《j),二者选择的pairi=《indexi,positioni》和pairj=《indexj,positionj》必须满足以下条件:(indexi《indexj)∨((indexi=indexj)∧(positioni≤positionj))。
[0020]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所述步骤5)中变量的声明位置由位置二元组pair表示,如果两个变量的pair相同,说明两个变量位于同一代码块内,两个变量的作用域也相同;声明语句去重算法解决同一变量对应两个pair的冲突情况,利用最小公倍数思想,选择作用域较大的声明位置,保证程序编译正确性。
[0021]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所
述步骤8)对所述步骤7)生成的程序框架中的控制流结构和语句执行情况预测打标时可选择的标签有executed、un-executed和unknown三种;所述步骤8)生成的不变式是一种使用代码行号,对预期覆盖率结果进行说明的等式。
[0022]
上述的基于结构化程序自动合成的代码覆盖率工具测试的方法,其特征在于,所述步骤9)调用的编译器覆盖率工具影响着覆盖率定义的方式,不同编译器对覆盖率定义的方式不同,使用不变式验证前先读取覆盖率报告进行格式转化,按照编译器规定的含义将执行次数翻译成数值格式,使用执行次数-1表示编译器给出覆盖率报告中的未观测点。
[0023]
本发明采用以上技术方案,具有以下有益效果:
[0024]
1.本发明利用结构化程序设计思想,将程序划分为若干控制流结构模块,并按照组合嵌套的方式拼接合成,有效降低测试用例程序复杂度,在很大程度上减轻了后续人工分析覆盖率工具错误的工作量的同时,保证了程序丰富的结构化信息。
[0025]
2.本发明提出不变式概念作为测试oracle,不变式规则屏蔽了不同语言语法的差异,利用行号作为测试基础,并利用可达性分析结果生成不变式,保证测试oracle的正确性和生成方式的通用性。
[0026]
3.本发明所述的一种基于结构化程序自动合成的代码覆盖率工具测试的方法,目前已发现c语言主流编译器llvm覆盖率工具多个错误。
附图说明
[0027]
图1为本发明实施例整体流程示意图。
[0028]
图2为本发明生成结构序列示意图。
[0029]
图3为本发明初始化位置数组示意图。
具体实施方式
[0030]
下面结合附图和具体实施例对本发明做进一步详细的说明。
[0031]
图1为本发明基于结构程序自动合成的代码覆盖率工具测试方法的流程示意图,如图1所示,主要包括如下步骤:
[0032]
步骤1):输入自动合成的结构化程序包含的控制流结构数量n,利用枚举算法重复排列生成多个控制流结构序列,其中一个结构序列可以表示为ss[n 1]={main,s1,...,sn}。
[0033]
所述步骤1),具体步骤包括:
[0034]
步骤1.1)根据输入控制流结构数量n,初始化结构序列数组ss[n 1],其中将所有序列的第一个元素初始化为main,表示所有控制流结构都存在于main函数方法体内。
[0035]
步骤1.2)本发明支持生成以下五种常见的控制流结构,分别为选择结构if/if-else和循环结构for/while/do-while。在确定控制流数量为n后,枚举算法进行可重复排列,由于控制流结构允许重复,每个位置上的元素都有5中不同的取法,因此共计生成5n种控制流结构序列,其中生成结构序列{main,s
for
,s
while
,s
ifelse
}的过程如图2所示。
[0036]
步骤2):根据控制流自身性质以及在结构序列中的位置,为序列中的每个结构s
index
初始化可插入点位置数组ps
index
[],每个位置数组内部元素为若干可插入点位置二元组pair;
[0037]
控制流结构序列中有n个结构,方法对序列中每个结构s
index
初始化一个可插入位置数组ps
index
,表示当程序中加入结构s
index
后,下一个结构s
index 1
所有可插入的合理位置。
[0038]
位置数组中的元素为二元组pair,形为《index,position》,表示当前结构的一个可插入点。其中index表示结构序列中待插入控制流结构的索引,取值范围0~n。position表示控制流结构内部代码块索引,即花括号“{”“}”括起来的部分。对于内部只有一个代码块的main函数、if结构、for/while/do-while循环结构,position取值只能为0;而对于内部有两个代码块的if-else结构,position取值可为0或1。
[0039]
位置数组初始化算法如下:当index=0时,ps0初始化为[《0,0》];当index=i时,对应控制流结构为si。如果此结构为if/for/while/do-while,内部只有一个花括号括起来的代码块,则psi=ps
i-1
《i,0》;如果此结构为if-else,内部有两个代码块,则psi=ps
i-1
《i,0》 《i,1》。
[0040]
结合实际结构序列{main,s
for
,s
while
,s
ifelse
}对初始化位置数组的过程进行说明,初始化过程如图3所示:
[0041]
(1)当index=0时,控制流结构为main。此结构只有一个方法体,因此位置数组ps0=[《0,0》],即s
for
可选择的插入点仅为main函数(index=0)的方法体内(position=0)。
[0042]
(2)当index=1时,for结构只有一个内部代码块,因此更新位置数组ps1=[《0,0》,《1,0》],说明下一结构s
while
有两个可插入位置,分别为main结构和for结构内。
[0043]
(3)当index=2时,while结构也只有一个内部代码块,因此更新位置数组ps2=[《0,0》,《1,0》,《2,0》]。
[0044]
(4)当index=3时,if-else结构有两个内部代码块,更新位置数组ps3=[《0,0》,《1,0》,《2,0》,《3,0》,《3,1》]。
[0045]
步骤3):以步骤1)获得的结构序列和步骤2)获得的每个结构对应的位置数组作为输入,搭建由main函数和控制流结构组成的程序框架,搭建过程中使用枚举加去重算法的方式,为每个控制流结构s
index
(1≤index≤n)从位置数组ps
index-1
[]中选择一个合理的pair作为控制流结构插入点,当所有s
index
(1≤index≤n)都确定了对应插入位置,程序框架搭建完成;
[0046]
步骤3.1)当index=1时,控制流结构s1从位置数组ps0[]选择一个插入位置二元组pair,因此只能选择《0,0》。
[0047]
步骤3.2)当index》1时,控制流结构s
index
从位置数组ps
index-1
[]选择一个插入位置二元组pair,此二元组的选择需要满足去重算法的约束。
[0048]
步骤3.3)去重算法约束如下,其规定两个控制流结构si和sj(i《j),二者选择的pairi=《indexi,positioni》和pairj=《indexj,positionj》必须满足以下条件:
[0049]
(indexi《indexj)∨((indexi=indexj)∧(positioni≤positionj))
[0050]
如果不满足此条件,则说明这种方式排列的程序框架是重复的,因此被去重算法舍弃,直接选择下一轮的插入点位置pair。
[0051]
步骤4):依照语法规则约束,为每个控制流结构随机选择合理的表达式作为条件判断语句,并随机插入若干表达式语句、赋值语句、跳转语句等丰富生成程序的语义信息,具体步骤如下:
[0052]
步骤4.1)设置控制流结构条件语句。不同结构具有不同的判断条件或循环条件。
选择结构if和if-else要求条件语句为布尔表达式;for循环结构的条件语句包含初始化语句、判断条件语句、控制条件语句;while和do-while的条件语句为布尔表达式,通常为一个进行自增的变量值判断。因此,本发明对结构序列中每个结构按照其语法要求分别匹配合理的条件语句。
[0053]
步骤4.2)条件语句变型。在符合语法规则的基础上,发明中对条件语句进行一系列变型,比如无终止条件的for循环,恒为真或恒为假的条件表达式,用于后续对程序执行情况预测提供信息。
[0054]
步骤4.3)合理添加表达式语句、赋值语句和跳转语句。除跳转语句外,其他语句不直接影响程序执行流程,方法体中的基本语句按照其出现先后顺序依次执行,发明中包含变量声明、变量自增自减、分配指针内存空间等语句。弱跳转指令影响当前结构以及其内部代码块的执行流程,发明中包含循环内break语句。强跳转指令影响程序整体的执行流程,发明中包含return语句和exit函数。
[0055]
步骤4.4)程序框架确定后,程序框架确定后,s3的位置数组ps3:[《0,0》,《1,0》,《2,0》,《3,0》,《3,1》]为当前所有可插入位置,上述语句在添加到程序框架时,采用乱序插入策略,保证同一方法体内语句执行顺序的随机性,同时还需满足以下约束条件:
[0056]
(1)基本语句可添加到任意位置;
[0057]
(2)弱跳转指令只能添加到循环结构中;、
[0058]
(3)强跳转指令中的return和exit语句不限制插入位置。
[0059]
步骤5):步骤4)中不同条件判断语句、表达式语句或赋值语句可能用到同一变量,故引入声明语句去重算法,为每个变量选择在当前程序中声明位置的下界,并在位置信息上界到当前下界中随机选择一位置信息插入声明语句,保证生成程序可正确编译,具体步骤如下:
[0060]
步骤5.1)遍历程序中所有使用到的变量,保存其出现位置信息。
[0061]
步骤5.2)如果位置信息为空,说明未使用到此变量,不需要声明;如果只有一个位置信息,说明此变量只使用过一次,因此此位置信息即为声明语句的下界,声明语句可以选择该位置信息的任意上层节点;如果有不止一个位置信息,说明此变量有过多次使用,此时需要找到两个位置信息的最小上界,作为此声明语句的下界。
[0062]
步骤5.3)所有变量的声明语句上界为main函数外,也就是全局变量,因此变量声明语句可以从上界全局变量到步骤5.2)计算的声明语句的下届中随机选择一个位置信息,作为此变量声明语句的插入位置。
[0063]
步骤6):分析步骤5)中确定的控制流结构、判断语句和跳转语句,消除显式死循环。由于在步骤4)中对控制流语句进行变型,引入了无限循环结构,需要遍历控制流结构序列{main,s1,...,sn},并对其中的每个控制流结构si进行显式死循环判断,具体步骤如下:
[0064]
步骤6.1)si为main函数或选择结构if或if-else,无序进行判断;
[0065]
步骤6.2)si为循环结构,如果(1)此循环没有循环终止条件语句;或(2)循环终止条件语句恒为真,则需要判断循环内部代码块中是否包含跳转语句;
[0066]
步骤6.3)如果循环内部代码块中不包含任何跳转语句,此循环结构为显式死循环,因此需要在内部代码块中随机加入return/exit/break等跳转语句;如果内部代码块中包含跳转语句,但在不确定是否执行的情况下,默认为非显式死循环,这种情况在执行编译
器脚本时再进行处理。
[0067]
经过此步骤可以消除程序中的显式死循环,但为保证程序语义的丰富性没有强制消除可能存在的全部死循环情况。因此在后续执行源文件生成覆盖率报告时,对执行时间进行判断,如果超过3秒则将此程序标记为timeout_error,后续由人工处理。
[0068]
步骤7):向内部无任何结构语句的控制流结构,添加空语句,搭建完整结构化程序,并对应程序合成测试程序源代码。
[0069]
如果控制流结构代码块没有任何语句,在生成程序时将产生没有花括号和内层语句的控制流结构,这样生成的程序源代码在编译时将产生错误。因此在完成上述插入表达式语句、跳转语句、声明语句后,对代码块为空的结构添加空语句“;”,以避免编译错误。
[0070]
步骤8):对步骤7)中生成的结构化进行执行情况预测,按照明确执行、明确不执行和不明确执行情况对控制流结构和语句打标,结合程序结构化信息和执行情况打标结果,生成不变式,具体步骤如下:
[0071]
步骤8.1)控制流结构s执行情况打标规则如下:
[0072]
(1)如果包含s的上层结构被标记为un-executed,s也为un-executed;
[0073]
(2)如果在遍历与结构s同层的其他结构时,遇到跳转语句,则将s标记为un-executed;
[0074]
(3)如果控制流结构a与结构s同层,根据前序打标签结果,控制流结构a中包含一定执行的终止语句,则将结构s标记为un-executed
[0075]
步骤8.2)控制流结构s内层代码块的执行情况由自身结构和条件表达式性质决定,s内层代码块执行情况计算规则如下(如果s为if-else结构,else_body代码块执行情况如下):
[0076]
(1)如果条件表达式和自身执行情况任意一个为un-executed,内层代码块也为un-executed(else_body为executed);
[0077]
(2)如果条件表达式和自身执行情况任意一个为unknown,内层代码块也为unknown(else_body为unknown);
[0078]
(3)如果条件表达式和自身执行情况两个均为executed,内层代码块也为executed(else_body为un-executed)。
[0079]
上述规则的优先级(1)》(2)》(3)。
[0080]
步骤8.3)生成不变式。本发明引入不变式概念,表示通用的测试oracle。不变式是一种使用行号描述程序执行流程的约束,例如某两行之间执行次数相等、某行执行次数应为零等等。生成不变式主要利用前序步骤的执行情况标签和结构体自身性质,生成不变式的规则如下:
[0081]
(1)对于标记为executed的控制流结构和语句,执行次数一定大于0;
[0082]
(2)对于标记为un-executed的控制流结构和语句,执行次数一定为0;
[0083]
(3)在main函数中,所有的强制跳转语句执行次数之和不大于1;
[0084]
(4)main函数入口的执行次数一定为1;
[0085]
(5)对于同一代码块中同层的非循环结构和语句,如果同被标记为executed,则对应行号的执行次数相等;
[0086]
(6)ifelse结构中,if_body代码块和else_body代码块执行次数之和等于ifelse
条件表达式的执行次数;
[0087]
(7)对于没有循环终止条件的循环结构,循环条件执行次数等于循环内部语句的执行次数;
[0088]
(8)循环结构的条件表达式执行次数不小于循环内部语句的执行次数等等。
[0089]
步骤9):调用编译器覆盖率工具,生成步骤7)中测试程序源代码对应的覆盖率报告,利用步骤8)中生成的不变式对覆盖率报告进行正确性测试,如果报告不满足不变式,认为覆盖率工具可能存在错误。具体步骤如下:
[0090]
步骤9.1)调用编译器覆盖率工具测试脚本,判断脚本执行情况,源程序是否正确编译、可执行程序执行是否超时以及是否正确执行生成了有效的覆盖率报告。
[0091]
步骤9.2)将生成的覆盖率报告转化成数组report[]。report[line]=count表示覆盖率报告中行号为line的代码执行次数为count。不同编译器对执行情况的定义不同,例如gcc中使用“#####”字符串表示此行未执行,但llvm中使用数字0来表示。
[0092]
步骤9.3)读取步骤8)中生成的不变式规则对report[]进行正确性验证,如不满足不变式规则,则认为覆盖率工具可能存在错误。
[0093]
以上所述仅为本发明的较佳实施例,但此处所描述的具体实施例仅仅用以解释本发明,并不用于限定本发明。任何熟悉本专业的技术人员,在不脱离本发明的原理和精神的情况下依据本发明的技术实质对以上实施例所做的任何简单修改,等同变化与修饰,均应包含在本发明的保护范围之内。
再多了解一些

本文用于企业家、创业者技术爱好者查询,结果仅供参考。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

相关文献