APP下载

一种提高软件可测试性的诊断测试方法

2020-01-16屈晓光胡玉露

电子技术与软件工程 2019年22期
关键词:测试人员源代码代码

文/屈晓光 胡玉露

在软件的开发与测试过程中一直存在可测试性的问题,那么到底什么是软件的可测试性,对于开发和测试人员来说针对具体的软件版本要进行深入测试又存在怎样的实际困难,需要我们认识清楚,以便把握问题实质。

先来看“软件可测试性”的概念,什么是“可测试性”?按照业界的定义,软件的可测试性是指软件发现故障并隔离、定位其故障的能力特性,以及在一定的时间和成本前提下,进行测试设计、测试执行的能力。James Bach 这样描述可测试性:软件可测试性就是一个计算机程序能够被测试的容易程度。

1 提高软件可测试性时面临的难题

以下是一个常见的软件可测试性检查表:

·简单性-“需要测试的内容越少,测试的速度越快。”

·稳定性-“改变越少,对测试的破坏越小。”

·易理解性-“得到的信息越多,进行的测试越灵巧。

·可操作性-“运行地越好,被测试的效率越高。”

·可观察性-“所看见的,就是所测试的。”

·可控制性-“对软件的控制越好,测试越能够被自动执行与优化。”

·可分解性-“通过控制测试范围,能够更好地分解问题,执行更灵巧的再测试。”

通过上述的描述可以对可测试性有一个定性的理解,但是仍然比较抽象,具体如何体现,还是不很清晰,即实现方法不明。

对于开发和测试人员所面临的实际调测的问题比较分散,但是相对具体,总结了一下,可能并不全面,常见困难应该有所涉及:

1.1 测试人员熟悉代码的程度比较弱,影响深入测试效果

图1:异常测试系统运行模式图

图2:DTSDM 模块探测点设计图

测试人员中能熟练编程的不多,深入把握软件代码难度大,定位系统测试只是做黑盒,影响测试设计的进一步深入;

1.2 软件运行过程中各种信息获取不灵活

直接涉及软件可测试性接口问题,常规是在代码中加打印获取,弊端较多。目前产品中已经做了不少有益实践,如异常探针、DO LOG、CDT 等工具大大加强软件信息的收集,不过专业性强,一般人员掌握难度大,还难以大范围使用,影响效果;同时提取信息范围相对确定,不能灵活变化

1.3 对软件实施各种异常测试比较困难

软件对各种异常处理往往存在大量缺陷,异常测试是进一步加强版本质量的关键,但是如何方便构造异常条件,运行众多的异常用例难有系统化的方式,软件从单元到模块到系统规模越大越难展开

1.4 当系统出现异常时,各模块间协同定位比较麻烦

当系统出现异常时,如何定位问题出现在哪里?往往根本原因隐藏较深,涉及众多模块交互运行,环环相扣直到最终才在某一模块出现错误,即使周边模块只有少量信息需要跟踪,也需要各模块开发人员合作并下临时版本来跟踪追查,费时费力。当然测试人员更是难以出力。

2 解决难题的思路

上述问题在软件开发与测试过程中各有侧重,似乎难以综合,但是仔细分析却也具有一定相关性,根本约束有两个:对软件处理行为了解越多越有利测试,直接影响测试有效性;对软件运行过程相关信息的收集乃至改变越容易越有利测试,即影响测试有效性也影响到高效性。

图3:代码统计图

图4:脚本编写画面

根据前面问题的总结,确定了如下研究目标:

(1)更系统地把握软件行为;

(2)更方便地跟踪定位故障;

(3)更直接的软件异常测试。

研究的重点也是围绕着两个约束来进行,先来看第一个约束:对软件处理行为了解越多越有利测试。这当然是一个望大的条件,但是面对超级复杂的产品软件,要想完全把握每个模块的每行代码是不现实的。开发人员了解代码多一些,也只限于所负责模块和相关模块,测试人员则更少。如果单纯从代码的角度来加强学习掌握,即走白盒路线是难有出路的,但是纯黑盒也是不行的,于是走灰盒的路线进入视野,即我们看重的是软件在实现什么功能,其处理行为是什么而不是具体的代码行,如果找到一种适当的方式来使软件行为得以显现就达到目的,我们要做到的是“熟悉软件行为,开展灰盒测试”,关键是要能降低应用门槛。

如何找到适合的做法呢,基本的想法就是在源代码中插入探测点,对探测信息进行分级设计,使探测点在软件代码中进行合理分布,为此形成一个关键的想法:将流程图标识在代码中。详细设计已经将模块的功能分解至函数级,做出了详细的工作流程图,但是在实现代码后代码本身并没有直接的体现,熟悉软件的人必须对照详细设计文档来走读代码从而了解软件行为,如果在设计实现代码时就有手段将主要功能处理及逻辑关系于代码中标识出来,就相当于给代码做了个CT 扫描,形成一个灰盒模式的软件事务处理图,即体现了软件代码所做的主要工作又屏蔽掉了多余的实际代码,去繁就简,就如同探察人体,将血肉透视掉,看到经络与穴位。

另一个约束:对软件运行过程相关信息的收集乃至改变越容易越有利测试。这涉及对软件运行进行诊断与测试,包括定位故障的过程和异常测试的过程。这个方面其实早已经有可用的技术,即利用IDT(Integrated Debug&Test Tool)进行代码异常测试的方法。这里将主要的工作原理再说明一下。

软件代码异常测试系统的基本运行模式如图1所示。

核心思路即在是源代码中嵌入可定制的脚本来运行,即可读取软件相关信息也可改变相关信息,从而提供诊断与测试的途径。

在第二个技术点的基础上结合第一个技术点的设想,可以发现两者有很好的融合,在软件功能处理打点位置设计好后,利用技术点二中探测函数以宏的形式插入源代码,即实现了本案中从可测试性设计到可测试性执行的转换。在本案中提出构建IDTE 环境的构想,即Integrated Diagnos& Test Environment。

3 思路的实践情况

3.1 可测试性设计

依据上述两个主要的技术解决思路,结合相应测试工具给出测试项目的设计。

首先是可测试性设计的尝试,即根据代码业务处理功能分析进行探测点的布局,针对仿真模块DTSDM、DTLACDP、DTTFDM 的代码进行了研究,主要从业务处理的角度选择相应的探测点位置,DTLACDP、DTTFDM 模块相对简单,复杂的是DTSDM模块,如图2示。

图2为DTSDM 模块代码探测点设计,右侧展开的树为SDM 模块处理中最为复杂的20ms 业务帧前反向处理功能实现,通过不同颜色来表示整个处理中功能分级展开,体现代码处理行为,基本上五级已经足够。右侧展开的树中未标识颜色的节点为不关心的代码部分,由于是手工作图,所以保留。显然当代码设计实现过程中逐步增加探测点后,需要有自动化的方式来生成类似的逻辑图,才能有实用性,这个相关技术是存在的,就不在本文展开,留待后续分解。

代码中探测点位置布局做好后,就可以结合技术点二的方式在实际代码中进行打点宏插入了。应用代码引用的IDTE 基本宏定义为

extern BYTE g_bAbProcFlag;

extern void IDT_AbProc(WORD wSignal,void * pBuffer,DWORD dwSize,DWORD dwAssistCode,VPID *ptSelfVPid,VPID *ptDestVPid);

#defineIDTEPROC(wSignal,pBuffer,dwSi ze,dwAssistCode,ptSelfVPid,ptDestVPid) if(g_bAbProcFlag==1){

IDT_AbProc(wSignal,pBuffer,dwSize,dwAssistCode,ptSelfVPid,ptDestVPid);}

以上面DTSDM 模块处理20ms 业务帧时的处理步骤为例,消息EV_S_SignalOnFrameOffset 的处理由函数ProcessSignalOnFrameOffsetMsg 进行,其下一级打点的记录为:

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_RevFrmPreProcs,&(ptAbistDataBuf->tAbistComDataBuf),。。。);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_ProcsPreamble,NULL,0,0,NULL,NU LL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_StopSendIdleFrm,NULL,0,0,NULL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_AirLinkQualityDetect,NULL,0,0,NU LL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_DemuxRevFrms,&tDemuxInputVar,si zeof(T_RevSlctedFrmInf),0,NULL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_DispatchRevFrms,&tDemuxOutputVa r,sizeof(T_DemuxOutputPara),0,。。。);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_GetMuxConditon,NULL,0,0,NULL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_GetMuxInf,NULL,0,0,NULL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_MuxFwdFrm,NULL,0,0,NULL,NULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_SlowDownRate,NULL,0,0,NULL,N ULL);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_SetFwdPreProcsInputPara,&tMuxOut putVar,sizeof(T_MuxOutputPara),0,。。。);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_PreProcsAndSendFwdFrms,&tPrePro csInputPara,。。。);

IDTEPROC(IDTE_ProcessSignalOnFrame OffsetMsg_CapacityMeasuring,NULL,0,0,NULL,NULL);

针对函数DispatchRevFrms 其下一级的记录为:

IDTEPROC(IDTE_DispatchRevFrms_Disp atchRevFDCHFrame,&(ptInputVar->atRevFCHT rafficTable[ucCircle]),。。。);

图5:显示结果图

IDTEPROC(IDTE_DispatchRevFrms_Disp atchRevFDCHFrame2,&(ptInputVar->atRevDCC HTrafficTable[ucCircle]),。。。);

IDTEPROC(IDTE_DispatchRevFrms_SaveRlpRevBlock,。。。);

IDTEPROC(IDTE_DispatchRevFrms_Rev NoDataProcess,NULL,0,0,NULL,NULL);

IDTEPROC(IDTE_DispatchRevFrms_SDM SendRevFrmToRLP,ptSDMDataToRLP,sizeof(T_AsdrSDMDataToRLP),0,。。。);

所打点位置与逻辑图中相一致,在具体布置探测点位置时有几条准则可以依据,总结如下:

(1)要注意处理点是在主流程中还是进入了函数调用——打点级别归属关系,区分相对级别;代码中调用函数是否打点分三种:内部无打点本身不打点(不用理会),内部有打点本身不打点(一级逻辑),内部有打点本身也需要打点(二级逻辑)。

(2)注意局部位置上不同分支处理的表示关系——if/else if/else 的分支打点。

(3)反映功能覆盖的处理点选择打点——入口、出口,中间处理点尽量减少同一分支的打点个数,即同一大分支中只选择一个重要节点即可(一般是最后一个)。

(4)除了反映软件功能覆盖的功能处理点要打点外(入口、出口、中间重要处理点),其它处理点打点选择——异常测试点、信息统计点。

上述(1)中所指的一级逻辑即某函数本身不打点而其内部有打点其实有很大用处,本例中体现在与异常探针的结合,原有代码中已经将异常探针进行了大规模的布局,处理中的各种异常位置都有分布,利用这个成果,在进行IDTE 探测点布局时可大大减少对异常位置的打点,表现为:

其中函数ProcessSignalOnFrameOffsetMsg为二级逻辑,而函数ExcpReport 为一级逻辑,这种情况出现时其内部的探测点等同地出现于ExcpReport 所在位置。

在代码中统一布局探测点整体效果是否有效尚有两个疑问,一个是探测点的数量规模,一个是事先从业务角度选择好的探测点在测试应用中是否够用,这两方面还需要通过实际应用来检验。

根据对DTSDM 源代码进行探测点实现,目前的结果统计如下:

源代码行数如图3所示。

所有IDTEPROC 宏打点位置为225 处,基本是百行代码打一个点,由于是对老模块代码进行设计,同时按集成和系统测试的角度进行功能分解,大致是这样规模,如果是新设计模块从单元测试开始可能会增加探测点数目。

3.2 可测试性执行

当代码中已经加入了对详细功能处理进行布点的探测点之后,对测试有何种好处呢,那就结合案例进行一些具体的介绍,体现其使用优势。

首先是异常测试的进行,在探测点相对完整的布局下则可发挥特长。在选择的探测点位置通过脚本可以进行异常变量/异常流程的设定,方便产生异常条件进行异常测试。下例进行一个简单说明:

信令模块会向SDM 模块发送EV_S_AbafActivateSDM 消息,其中带有所分配资源的帧偏置信息ucSDMFrameOffset,一个字节有效取值为0-15,如果取值不对则报异常并结束对此消息的处理,相应的定制脚本如图4所示。

红色标识处即为进行异常取值的设定,将消息中的这个字段改为非法值,代码继续处理后会发生相应异常,异常探针的信息如前述也通过相应探测点由脚本捕捉,进行显示,结果如图5所示。

顺带注意一下定制信息中IDTE_EntityEntry_normal 这个打印,在源代码中这个探测点位于进程入口处

这是一个可有多种业务输入消息的探测点,用处也很大。

4 结束语

结合文章开始所描述的测试问题及设定的研究目标,看一下效果的可行性及可以进一步研究完善的内容。上述方案的实施对于非代码开发人员快速掌握软件代码功能,了解软件行为具有去繁就简的效果,当然需要提供自动扫描代码生成逻辑图的能力,这在探测点信息定义上还需要随之做完善。

实现了探测点插入的软件版本在运行中进行异常测试与跟踪定位将有很大帮助,案例只体现了一部分应用特点,其它如进行流程自测、定制打印显示、信令跟踪等功能都可充分利用,此外一些更好优点可随实际应用而扩展,如对软件逻辑运行跟踪回放、基于功能点的覆盖率统计分析等。由于验证内容与源代码是有效隔离的,在实际调试测试过程中,始终可以保持代码的“干净”,对程序可维护性也有一定帮助。后续希望在软件模块设计编码环节也增加作用。

本文所介绍的软件可测试性设计及执行方法具有较大通用性,尤其是针对前台嵌入式软件而实现了系统架构,对于增强软件诊断测试手段有一定作用。

猜你喜欢

测试人员源代码代码
人工智能下复杂软件源代码缺陷精准校正
基于TXL的源代码插桩技术研究
创世代码
创世代码
创世代码
创世代码
软件源代码非公知性司法鉴定方法探析
高校分析测试中心测试队伍建设方案初探
揭秘龙湖产品“源代码”
犯罪心理测试人员素质要求分析