基于桩函数动态赋值的软件覆盖率测试方法
2020-12-23万东燕罗睿梅李俊山
万东燕, 罗睿梅, 李俊山, 陈 铖
(上海无线电设备研究所,上海201109)
0 引言
软件测试[1]是软件研发过程中的一个重要环节,通过软件测试可以及时发现软件缺陷,保障软件的安全性和可靠性。单元测试是软件开发过程中最基础的测试项,是软件的独立单元在与程序的其他部分相隔离的情况下进行的测试。其中代码覆盖率能够体现代码的执行情况。测试人员可以通过覆盖率指标,分析代码执行范围,完善测试用例,有效提高软件测试质量。
在软件测试的过程中,执行单次的测试用例时,某些函数的输入变量激励会在代码执行过程中发生动态变化。若测试用例中的输入变量激励不能对应进行动态更新,则需激励更新才能进入的相关语句无法完成测试,代码覆盖率测试也无法完成。为了解决这一问题,测试人员需要在设计的测试用例中模拟输入变量激励的变化条件,来完成测试。本文结合专业的测试工具,研究了变量激励可动态更新的桩函数赋值法,并设计灵活的测试用例,以保障测试质量、提高测试效率。
1 软件的单元测试
1.1 单元测试方法
单元测试的主要目的是验证软件单元是否满足详细设计规格说明,发现需求和设计中的错误。测试用例是影响单元测试效率和效果的重要因素[2]。本文采取黑盒与白盒结合的方法对软件进行测试。利用黑盒测试方法中的等价划分法和边界值分析法来设计测试用例。等价划分法[3]基于输入条件的等价类评估,在每个等价类中选取有代表性的测试用例,从而达到等价类覆盖的要求。由于程序错误常在定义域和等价类的边缘被发现,所以需要对每个测试变量进行边界值分析。边界值分析[4]是等价类划分的精炼,即选择每个类的边界或终点进行测试。
覆盖率是软件开发过程中重要的度量指标,具体包括语句覆盖、分支覆盖、条件覆盖等。覆盖率测试[5]作为一种白盒测试,其主要作用包括:a)评估测试质量,根据软件代码的覆盖率报告,发现漏测场景,为测试人员及时补充新的测试用例提供指导;b)帮助识别冗余代码,对程序代码进行优化与重构。
1.2 单元测试工具
Testbed是一款专业的软件测试工具,可用于生成和维护测试脚本,编译并运行测试可执行程序,查看测试结果和覆盖率数据。其中,Testbed/TBrun模块可执行软件的单元测试[6]。该模块可以在运行测试用例对软件功能进行测试的同时,分析得出软件单元相应代码的测试覆盖情况,评估测试状态,从而为设计新的测试用例提供指导。
2 测试用例的设计
2.1 测试用例生成基础
(1)单元测试环境
为了方便对嵌入式软件进行单元测试,在测试前首先要去除代码中的硬件相关部分,将其移植到Testbed相应的测试环境中。移植的过程不会影响软件的功能,测试环境与现实环境差异不大,能够确保测试的有效性和可靠性。
单元测试的对象是不可独立运行的函数单元。测试时需要建立两种辅助测试模块:驱动模块(driver)和桩模块(stub)。驱动模块用于模拟被测函数的上层模块,桩模块用于模拟被测函数在执行过程中所调用的其他函数,以保证被测单元能完整闭合地运行。在单元测试中,被测函数可能调用多个其他函数,故可能存在多个桩函数。
(2)桩函数
桩函数是根据测试需要编写的,用于替代被测函数调用的函数。桩函数有两种情况:一是该桩函数在被测函数中不需要返回特定值,不需要作其他处理;二是该桩函数在被测函数中需要返回特定值,不同返回值会影响代码运行与输出结果,需要根据测试需求,在Testbed/TBrun模块中进行相应的返回值设置。
在桩函数中设置返回值时,通常只支持输入变量激励的一次性静态赋值,在代码的运行过程中不能进行修改。由于这一局限,导致无法直接对在单次执行过程中需多次变更输入变量激励的函数进行测试。同时这一问题会在覆盖率测试中反映,由于对应的分支和语句无法被执行,所以覆盖率测试也无法完全完成。为了解决这一问题,需要分析进入不同分支的变量激励的更新要求,并设计可动态更新的桩函数返回值,来模拟进入相应分支的条件,完成测试。
以某数字信号处理软件为例,测试其误差处理函数DJDMBJC时,需要调用函数Find Max-Point来获取并返回最大值变量max_data。在测试软件运行过程中,函数Find Max Point中变量max_data的值会在执行过程中动态更新,软件通过判断变量值所在范围,进入相应程序分支,相关程序流程如图1所示。
图1 误差处理函数测试程序流程图
由图1可知,该段代码调用了两次函数Find-MaxPoint,并读取max_data的值,判断该值并进入对应的执行语句。对函数DJDMBJC进行测试时,若要到达第二个判断框,则需在第一个判断处进入“否”分支,即满足max_data≤12。在该前提下,若max_data的值无法更新,则只能进入第二个判断框的“否”分支,而无法进入与“执行语句2”对应的“是”分支,无法对该段代码完成测试覆盖。因此,在测试中,需要研究桩函数返回值的设置方法,实现输入变量激励的动态更新。
2.2 桩函数返回值赋值法
为了解决2.1节中由于被测单元函数所调用桩函数的输入变量激励值无法更新,导致覆盖率测试不能完成的问题,提出一种桩函数返回值动态赋值方法。根据Testbed/TBrun模块中桩函数的代码运行方式,在桩函数的后台代码段中构造并声明一个整型变量count,用来记录不同赋值点的位置。位置i对应的返回值ai即为该时刻的变量值,当函数运行到count值所对应的位置i时,将返回值ai赋值给变量max_data,从而实现被调用的桩函数输入变量激励的动态更新。具体实现过程如图2所示,其中n代表变量激励动态更新的次数。
将上述方法应用于2.1节函数DJDMBJC的测试用例设计。执行改进后的测试用例,将两次调用桩函数后的变量max_data激励值从11更新为13,即可先进入图1中的第一个“否”语句,再进入第二个“是”语句,实现不同分支的全部执行。
图2 桩函数返回值动态赋值程序流程图
2.3 测试用例的设计实现
本文被测软件中,变量max_data的取值范围为0~25。由判定条件max_data>12可知,12为判断边界值,即该变量的边界值为0,12和25。对变量进行等价类与边界值分析,结果如表1所示。
表1 等价类与边界值分析
由图1可知,当max_data≤12时,程序会进入第一个“否”分支,然后对已更新的变量max_data值进行第二次判断。因此,在进行边界值测试时,要考虑两次函数调用时变量的判断边界。结合变量max_data的判断边界,对测试用例进行覆盖有效等价类和边界值测试与覆盖无效等价类和边界值测试分类,实现程序边界的完整分析与覆盖,测试用例设计如表2所示。其中max_data_1和max_data_2分别代表第一和第二个判断框对应的max_data的值。通过对两处的max_data进行分类赋值,即可达到函数功能以及语句与分支的全部覆盖。
执行改进的测试用例前后,函数DJDMBJC的测试覆盖率如表3所示。在函数DJDMBJC的测试过程中,执行改进的测试用例,语句与分支判定的覆盖率分别由90%、93%提高到100%,解决了函数测试分支无法到达的问题,实现了该函数的覆盖率测试,提升了测试质量。
表2 测试用例表
表3 函数DJDMBJC测试覆盖率 %
3 结论
本文以Testbed软件为测试工具,提出了变量激励可动态更新的桩函数返回值设计方法,解决了单元测试中语句和分支覆盖率测试不全的问题。结合等价类划分与边界值测试,设计全面且高效的测试用例,有效地精简了测试用例个数,提高了测试用例设计的准确性和测试效率,对提升测试质量具有重要的积极意义。