APP下载

一种基于C#的Cantata工具变更过程改进方法

2021-05-14王玉婷连红森

测控技术 2021年4期
关键词:插桩源码单元测试

周 毅, 王玉婷, 方 霞, 连红森

(中国航发控制系统研究所,江苏 无锡 214063)

航空发动机控制软件(简称控制软件)是一种嵌入式软件,根据DO-178《民航机载软件适航标准》的规定,属于安全关键软件[1]。为满足适航认证,控制软件必须要达成DO-178C提出的各项指标要求。其中,针对低层需求与高层需求的符合性这一目标,执行单元测试并建立追溯关系是一种常见的实现手段。

针对嵌入式软件开发环境和运行环境不一致的现象,单元测试具有可在宿主机环境下执行、能提早测试介入时机且最大程度降低测试活动对目标环境依赖性等优点;然而,单元测试也存在着的测试驱动难编写、测试程序难管理、测试结果难界定等问题。对此,市场上出现了一批如CppUnit、JUnit等开源测试框架[2]和Cantata、TestBed、Qt、TBrun等单元测试软件[3-5]。

其中QA Systems公司推出的Cantata单元测试工具,可提供基于DO-178B的覆盖率分析,目前已在国内外航空航天软件的单元测试活动中得到广泛应用[6-10]。该工具针对C/C++语言,通过使用EGT分析器提取源码信息,结合插桩器和自动封装技术,实现测试脚本一键生成;通过提供测试用例管理器,实现测试用例便捷管理;通过运行结果自动比对、覆盖结果树形分析技术,缩短测试验证时间,确保验证结论的正确性和完整性。

然而,由于Cantata工具在执行单元测试活动时所有过程均需基于服务器执行,而且工具对被测单元的隔离插桩过程与被测单元所属文件有直接关联。这就导致软件升级时,若被测单元所属文件发生变化,即使被测单元未发生更改,原有的单元测试用例也需要重新隔离插桩才能通过。由于隔离插桩过程需要人工操作,另外受到服务器响应和处理时间长的制约,在实际执行Cantata单元测试回归时,需要耗费大量时间和人力来更新未变更函数的隔离插桩。

目前,国内外的相关文献主要集中在对Cantata单元测试方法和工具使用的介绍说明[6-10]。针对本文提出的这一问题,尚未有具体解决方案。笔者提出了一种基于C#的Cantata工具变更过程改进方法。通过分析Cantata工具的单元测试插桩结果,提炼出工具的插桩规则,进而结合C#和正则表达式,完成源代码变更前后差异分析,并依照提炼的插桩规则,自动修改测试用例管理器中的测试脚本和被插桩后的代码,实现未变更函数的自动隔离插桩。从而解决人工操作烦琐和隔离插桩过程对Cantata服务器强依赖的问题。

1 基于C#的Cantata变更过程改进方法

1.1 整体方案分析

Cantata工具执行单元测试过程主要由源代码隔离插桩、测试脚本生成、可执行文件构建和运行这4个活动组成,各活动均由服务器执行并将相应结果返回给用户,具体如图1所示。

图1 Cantata单元测试原理图

由于Cantata工具使用C文件作为自动封装的最小单位(一个自动封装可包含多个C文件),当被测单元所处自动封装中的C文件出现全局变量、函数或外部函数调度变化时,即使被测函数没有任何变更,也必须更新自动封装,重新执行隔离插桩,才能确保单元测试用例执行通过。

Cantata测试用例管理器通过管理test_FuncX.c、test.mk和ipg.cop这3个文件来管控生成的测试脚本和被插桩代码。

其中,test.mk是测试脚本的makefile信息,用于指导Build构建器编译生成可执行文件;ipg.cop是测试级别配置文件,描述需要被隔离的全局变量和函数,指导Cantata工具自动生成被测函数FuncX()的隔离插桩信息;test_FuncX.c是被测函数FuncX()的测试脚本,用于存储被测函数的环境定义、覆盖率分析方式、测试用例和隔离插桩接口等信息。

据此,在进行工具二次开发时,通过执行代码分析,识别出变更后代码新增、删除的全局变量、函数和函数调用信息,再将这些信息按照Cantata单元测试的格式要求,更新到test_FuncX.c、test.mk和ipg.cop中,实现对未变更单元的测试脚本和被插桩代码的更新。二次开发后的Cantata单元测试原理如图2所示。

图2 二次开发后的Cantata单元测试原理图

由图2可以看出,基于C#的Cantata工具二次开发可以脱离对服务器的依赖,自动识别源码的变更信息,完成测试脚本和被插桩代码的修改。

1.2 Cantata插桩规则提炼

通过分析Cantata单元测试结果,对Cantata插桩规格进行了提炼。图3展示了某待测试文件XX.c的文件结构,包括全局变量GLB_a、函数FuncX()和FuncY(),其中FuncY()调用了一个外部函数UT_a()。

图3 XX.c文件结构示意图

当FuncX()作为被测函数时,Cantata工具对test_FuncX.c、test.mk和ipg.cop文件的插桩规则如下。

① test_FuncX.c中,待隔离函数FuncY()的插桩规则如下:

/* Iaolate for function FuncY */

void ISOLATE_FuncY(void){

REGISTER_CALL(“FuncY”);

IF_INSTANCE(“default”){return;}

LOG_SCRIPIT_ERROR(“Call instance not defined.”);

Return;}

② test_FuncX.c中,全局变量GLB_a量的隔离规则如下:

/* Global data */

int GLB_a;

/* Expected variables for global data */

int expected_GLB_a;

static void initialse_global_data(){

TEST_SCRIPT_WARNING(“Verify initialse_global_data() ”);

INITIALISE(GLB_a);

}static void initialse_expected_global_data(){

TEST_SCRIPT_WARNING(“Verify initialse_expected_global_data() ”);

COPY_TO_EXPECTED(GLB_a, expected_GLB_a);}

static void check_global_data(){

TEST_SCRIPT_WARNING(“Verify check_global_data() ”);

CHECK_MEMORY(“GLB_a”, &GLB_a, &expected_GLB_a, sizeof(expected_GLB_a));}

③ ipg.cop中,待隔离函数funcY()和UT_a()的插桩规则如下:

“--sm:--isolate:FunY()”

“--sm:--isolate:UT_a()#FunY()”

④ ipg.cop中,全局变量GLB_a的隔离规则:

“--sm:--access_variable:”XX.c”:GLB_a”

1.3 二次开发方法设计

基于C#进行Cantata工具二次开发时,主要难点在于源代码分析和变更差异比对。对此,以文件为单位,设计了文件信息的数据结构,具体的文件信息类图如图4所示。数据结构通过对头文件引用、宏、数据结构、全局变量、函数声明、函数等信息进行分类存储,实现变更差异的快速识别和比对。

图4 FileInformation类图

文件信息提取流程如图5所示。为便于使用正则表达式提取源码中的有效信息,首先需对源码进行规格化处理,具体为剔除源码中条件编译忽略的代码、注释代码、不规范和冗余的空格信息。由于条件编译的判断条件多使用宏信息,故需要先对源码进行一次宏定义分析,再按照定制的形式进行规格化处理,导出规格化后的源码。

图5 文件信息提取流程图

源码规格化后,按照各数据结构类型特点设计相应的正则表达式,依次提取头文件引用、宏定义、基本数据类型、特殊数据类型、函数声明、全局变量、函数信息,完成源码的文件数据结构提取。其中,特殊数据类型特指枚举、位域结构体和结构体类型,另外考虑到同义宏的存在,设计了递归方法执行同义宏的分类和存储。

完成变更前后源码的文件信息提取后,以文件为单位采用循环遍历的方式,判断并记录对应文件中所有全局变量、函数及函数调用的变更状态(共设计3种状态:增加、删除、无变化)。依据记录的变更状态,按照Cantata隔离插桩格式要求,更新用例管理器中未变化函数的单元测试用例脚本,实现未变更部分的自动隔离插桩。

2 项目应用实践与结果分析

在某项目升级过程中,应用基于C#的Cantata工具二次开发方法。通过选中变更前后源码和Cantata测试用例管理器的位置,一键运行后,完成受升级影响的非变更测试用例隔离插桩的自动修改。具体运行界面如图6所示。

图6 运行界面

更改结果显示,此次变更前后源码共涉及17个文件、9个全局变量、81个函数的变更。使用Beyond Compare工具比对变更前后源码并人工分析,结果显示与C#的Cantata工具二次开发方法提取的结果一致,信息提取功能和变更比对功能正常。

此次变更前共计有436个单元测试脚本,变更前后共影响到123个测试脚本的关联修改,修改量占28.2%。以其中一个关联修改的测试脚本为例,进行分析:task.c文件共有5个函数,比对变更前后的源码,其中仅task_bigLoop()函数里新增了函数调度ISM_Excute25ms(),会同步影响该C文件中其他4个未变更函数测试脚本的隔离插桩。观察分析对应未变更函数自动修改后的测试脚本可知,测试脚本中均按照格式要求完成了脚本修改,具体结果如图7所示。

图7 测试用例脚本修改结果

完成81个变更函数对应的测试脚本修改后,在Score环境下批跑所有的444个测试脚本,导出结果如图8所示。结果显示,所有自动隔离插桩的函数均通过,其中11个未通过的函数均为特殊实现原因导致覆盖率无法满足的函数,与自动隔离插桩过程无关。

图8 Cantata单元测试用例批跑结果

基于Cantata服务器进行人工手动隔离插桩时,平均每个测试脚本需花费大约10 min。使用二次开发方法后,平均只需要不到3 min即可完成所有未变更函数测试脚本隔离插桩工作。以本次123个测试脚本的关联修改为例,二次开发方法可有效节省约20.45人时,测试工作效率有极大提升。

上述结果证明,基于C#的Cantata工具二次开发方法可准确识别变更前后的源码信息并完成差异比对,能正确并快速实现未变更函数的自动隔离插桩工作。

3 结束语

通过分析航空发动机控制软件升级过程,发现在依赖Cantata工具进行单元测试回归时,存在未变更函数的测试脚本需重新人工手动隔离插桩,导致时间和人力耗费的问题,提出了一种基于C#的Cantata工具二次开发方法。项目实践与分析结果表明,该方法能准确识别变更信息,正确并快速实现未变更函数的自动隔离插桩,极大提升了基于Cantata进行升级过程的单元测试效率,为达成DO-178C中低层需求与高层需求的符合性这一目标提供了有力支撑。

目前基于C#的Cantata工具二次开发方法已在3个项目的5次升级过程中得到应用,结果均正确可靠。但相较于市面上常见的源码分析工具(如Eclipse CDT提供的API),本方法尚不支持函数内部语法分析,也未与同类型代码分析工具进行优劣比对分析,这些可作为后续研究的一个方向。

猜你喜欢

插桩源码单元测试
面向数据可靠传输的高译码率带反馈的LT码
基于TXL的源代码插桩技术研究
国内一站式工程设备租赁平台众能联合完成C2、C3两轮融资
浅谈开源操作系统的历史
企业如何保护源码
基于性能分析的自适应插桩框架
基于记录重播的嵌入式系统死锁检测方法
一年级上册第五单元测试
基于顺序块的嵌入式白盒测试插桩技术研究
一年级上册一、二单元测试