嵌入式软件部件测试可在目标机平台执行;如果不具备目标机环境,可基于宿主机平台[1-3]以全数字仿真[4]的形式模拟部件运行环境。基于宿主机开发部件仿真测试平台时,通常采用基于时钟驱动的循环调度[5]来模拟软件产品对周期性运行的部件所采用的定时调度,以便高保真地模拟软件产品在目标机上的行为。如果仿真测试平台运行于非实时、多任务操作系统上,定时执行的部件受外部进程影响,可能无法在规定时限执行结束,引起软件运行时序错乱,影响仿真结果的正确性。因此本文将部件定时循环调度进一步简化为计数循环调度,以程序循环计数取代基于定时器的时间度量:无论某次循环是否调度部件执行、执行几个部件,每次循环计数在逻辑上都等价于所有部件运行周期的最大公约数。一方面消除了定时调度中部件运行超时对软件时序的负面影响,同时避免了部件等待调度运行的周期间隙过长对仿真时间的浪费。关于循环调度的研究,主要集中在对多核处理器进行循环结构执行效率的优化方面[6-9]。分时系统中有时也将时间片轮转调度(Round-Robin)称为循环调度[10],适用于相互间无功能耦合的多进程调度;而软件产品的各部件之间存在紧密的功能耦合,在单个部件执行结束前不宜受制于时间片结束而强制切换部件的执行,否则可能导致部件仿真测试结果错误。
测试平台接口包括软件部件和用例文件选择输入的人机接口;软件部件接口包括从用例文件中提取部件输入和将部件输出存储到测试结果文件。
为适应不同的软件部件测试场景,设置4种部件测试模式:单部件单用例文件手动循环执行、单部件多用例文件自动循环执行、多部件单用例文件自动循环执行和多部件多用例文件自动循环执行。其中单部件单用例文件手动循环执行模式最简单易行,主要适用于首轮部件测试,便于逐个判断每个测试用例文件在各软件部件上运行的结果是否正确;其他部件测试模式主要适用于软件部件回归测试,以加快回归测试进度。
为方便测试执行,将待测试软件部件从1连续编号。在启动软件部件测试执行时,根据部件测试执行模式不同,以界面友好的方式提示软件部件编号并接受部件号输入;为防止软件部件号输入越界或非法,设置默认软件部件编号为1。
测试用例输入文件按软件版本和部件分级存放。如软件版本V1.00包含两个软件部件PartA和PartB,可将部件PartA所有测试用例输入文件集中存放在V1_00\PartA路径下,部件PartB的用例文件存放在V1_00\PartB路径下。为提高测试执行效率,可在测试平台内部设定部件测试用例文件路径,执行测试时只要输入或选择文件名即可准确定位。
由用例编号和用例文件名(NAMELEN代表约定的测试用例文件命名的最大字符串长度)组成的测试用例文件结构体类型定义如下:
typedef struct{
int tcFileNo;//用例文件自动编号
char tcName[NAMELEN];//用例文件名
}TESTSUITE;//用例文件结构体
由软件部件编号、用例文件数目、用例文件集合、用例文件路径(MAXTCNUM 代表从属于部件的用例文件数最大值,PATHLEN代表用例文件绝对路径包含字符数最大值)组成的软件部件结构体类型定义如下:
typedef struct{
int partNo;//软件部件编号
int tcTotalNum;//用例文件数目
TESTSUITE tcSet[MAXTCNUM];//用例集
char tcPath[PATHLEN];//用例文件存储路径
}TEST4PART;//软件部件结构体
所有软件部件(PARTNUMS代表被测软件部件的数目)及用例文件集合组成的数组定义如下:
TEST4PART swPartTests[PARTNUMS];
//软件部件与用例文件集合数组
软件部件外部接口分为输入、输出两种接口,输入接口为测试用例文件,输出接口为测试结果文件,均为.csv格式的文本文件。
为了简化测试用例注入方式,统一定义测试用例文件格式。约定首列为控制用例注入的时序节拍seq,可以连续(seq=0、1、2……)或跳跃(seq=0、1、5……)的方式递增,以便灵活地模拟测试输入保持时间;其余各列为数据类型和范围与各部件输入接口严格匹配的数值集合。
设A、B两个软件部件待测,以结构体形式(其中TYPEA和TYPEB代表适用的标准数据类型或自定义数据类型)定义各部件输入集合如下:
typedef struct{
TYPEA varAin;//来自部件A测试用例文件
}PARTAIN;//部件A测试输出结构体定义(输入)
typedef struct{
TYPEB varBin;//来自部件B测试用例文件
}PARTBIN;//部件B测试输出结构体定义(输入)
在测试结果记录和存储时,以结构体形式定义各部件输出变量的集合如下:
typedef struct{
TYPEA varAout;//部件A测试执行运算结果
}PARTAOUT;//部件A测试输出结构体定义(输出)
typedef struct{
TYPEB varBout;//部件B测试执行运算结果
}PARTBOUT;//部件B测试输出结构体定义(输出)
为了判断每个测试用例执行结果通过与否,需要建立各部件测试用例输入与测试结果输出的一一对应关系。定义结构体如下:
typedef struct{
int recNo;//部件被调度次数
int lasting;//部件单次调度执行时间
PARTAIN in;//来自测试用例的输入
PARTAOUT out;//与输入相关的输出
}PARTAOUTPUT;//部件A测试输出内容
typedef struct{
int recNo;//部件被调度次数
int lasting;//部件单次调度执行时间
PARTBIN in;//来自测试用例的输入
PARTBOUT out;//与输入相关的输出
}PARTBOUTPUT;//部件B测试输出内容
为了实时记录每个测试用例的执行结果,需要将测试用例输入与测试结果输出建立一一对应的关系。定义结构体如下:
typedef union {
PARTAOUTPUT PartA;//部件A测试输出
PARTBOUTPUT PartB;//部件B测试输出
}TESTOUTPUT;
与测试用例输入关联的待测软件部件测试输出缓冲区定义如下:
TESTOUTPUT testData[TSTBUFLEN];
//部件测试输出缓冲区
软件部件测试主体框架包括初始化和周期性调度两部分,流程如下:
图1 软件部件测试平台主体框架流程图
部件测试初始化包括软件部件初始化和部件测试平台初始化。软件部件初始化即调用软件部件初始化模块。部件测试平台初始化即根据选择的测试模式不同,对软件部件和测试用例文件进行定制化设置:
部件测试平台初始化流程如下:
图2 部件测试平台初始化流程图
上图部件测试平台初始化流程中的最后一步,即测试用例文件解析模块的主要功能是提取用例文件内容,以首列所有时序节拍数据初始化控制时序数组,用于控制各行测试数据的注入时机,作为软件部件周期性调度、输入接口数据维持或更新的依据;并以用例文件中第一行数据对当前被测软件部件输入接口变量进行初始化,其流程如下:
图3 测试用例文件解析模块流程图
部件测试周期性调度包括软件部件调度运行、部件测试自动化执行控制和测试结果即时记录三部分,主要功能是控制用例注入节拍、以不同模式控制部件测试不间断自动执行和单个测试用例文件执行结束后的结果输出等。
在部件测试调度执行过程中,为每个部件设置一个单独的调度计数变量cntA、cntB,便于测试结果输出时只保存输出缓冲区中的有效数据,避免将缓冲区中的大量无效数据写入测试结果文件,以免造成测试执行时间的浪费和测试结果判读难度的增加。
设变量r代表各软件部件调度周期的最大公约数,部件A的调度周期为p*r,部件B的调度周期为q*r,且p与q互质。则在测试平台调度循环程序中,以r作为计数单位,每次循环,变量r增1;当计数为p的整数倍时,调度部件A,cntA加1;计数为q的整数倍时,调度部件B ,cntB加1。
例如部件A调度周期为10ms,部件B调度周期为15ms,二者最大公约数为5ms。则每次调度循环(r增1)当作5ms,每2个调度循环(p=2)运行一次部件A,每3个调度循环(q=3)运行一次部件B。设部件A测试用例时序seq=0、1、3,相应用例文件中输入数据序列为0、11、33;时序为0时初始化部件A输入接口。则部件A调度运行情况如下表所示:
表1 部件A调度运行情况表
调度循环计数r |
部件A调度计数cntA |
部件输入接口变量varAin |
0 |
0 |
0 |
1 |
0 |
0 |
2 |
1 |
11 |
3 |
1 |
11 |
4 |
2 |
11 |
5 |
2 |
11 |
6 |
3 |
33 |
7 |
3 |
33 |
部件测试自动化执行控制包括利用来自测试用例文件的时序节拍数据(已转存入时序控制数组),检查当前调度节拍是否到达下一个时序控制点,测试输入数据是维持前一个调度循环状态,还是重新注入用例文件中下一组数据。
无论采用哪种部件测试自动化执行策略,都要保证与指定软件部件绑定的用例文件逐个顺序执行,不允许多个用例文件交叉运行或多个部件同时测试。
部件测试执行自动化控制流程图如下所示:
图4 部件调度时序控制图
对于单部件单用例文件手动循环执行模式,在指定部件上单个用例文件中所有输入数据全部执行结束,则该测试模式自然结束。其他模式下软件部件测试自动化执行控制方法如下:
针对指定部件,当前用例文件中所有测试输入处理结束,保持当前软件部件编号不变,再次执行测试用例文件解析模块,读取下一个用例文件进行解析,调度执行该部件,实时记录测试结果。直到所有测试用例文件执行结束。
由于所有部件测试用例格式是统一的,因此单个用例文件可包含多个部件的输入信息。但不同部件输入接口不同,使用同一个用例文件执行软件部件测试,要针对不同部件分别解析。
针对当前软件部件,当用例文件中所有输入处理完毕,再次运行测试用例文件解析模块,对该用例文件按照下一个部件的输入接口重新解析,然后调度运行新部件,实时记录测试结果,直到所有软件部件测试执行结束。
如果存在几个用例文件同属于多个部件的情况,需要在初始化时,为这些部件重复设置相同的用例文件名。
按照部件优先原则,参考单部件多用例文件自动循环执行模式,先执行第一个部件的所有用例文件,再执行第二个部件,直到完成所有部件测试。
本文设计的部件测试平台方案不考察部件调度周期,软件部件的调度由程序主循环运行节拍来控制。
为了初步验证部件运行时间性能是否满足要求,在部件调度执行过程中,记录每次调度开始、结束时刻,求差值,作为第i次调度时部件运行时间,存入testData[i].lasting中。一个用例文件执行结束,汇总最大、最小和平均执行时间;然后结合宿主机与目标机CPU主频的差异,粗略推算出目标机平台上部件执行的相关时间性能指标(该性能指标的准确性受宿主机操作系统的实时性、并发运行的进程数等因素影响)以供参考。
在测试用例文件处理过程中,每调度一次软件部件,产生一组测试结果,将该结果与软件部件当前输入数据一起暂存到测试输出缓冲区。如部件A第i轮调度执行记录包括testData[i].PartA.recNo、testData[i].lasting、testData[i].PartA.in.varAin和testData[i].PartA.out.varAout的正确赋值。
当前执行用例文件中所有数据处理完毕,一次性将测试输出缓冲区中有效输入、输出数据写入测试结果文件。为了多次记录单个用例文件执行结果,对比各次结果偏差,测试结果文件统一基于软件部件名、用例文件名和字母A~Z联合命名。如软件部件名称PartA,用例文件名称T_FUNC1_1,测试结果文件命名为PartA-T_FUNC1_1A …… PartA-T_FUNC1_1Z。
可将被测软件部件以开源文件、二进制文件、函数库等形式,与测试平台支撑软件一起编译链接,生成指定版本软件的部件测试平台可执行文件。在保持软件部件输入、输出接口不变的前提下,可在测试平台上直接替换被测软件部件,形成升级版测试平台软件可执行文件,支持软件部件回归测试。
某型号航空发动机FADEC控制软件数字仿真测试平台基于微软VS2010开发,直接参照软件产品的定时要求进行部件调度,在1ms定时事件处理函数中为5ms和20ms定时调度独立计数,在主程序中轮询各计时周期是否到达,并按需执行相应的部件调度。
测试人员基于高层需求设计了T25信号斜率故障诊断的用例。需求规定T25信号采集周期为5ms;斜率故障诊断周期为20ms,以最近5ms的采集值作为信号工程值,若当前周期工程值Signal与前一周期工程值Signal_1之差超过斜率阈值SlopeLimit,应判定信号当前周期斜率失效SlopeInv = 1;若持续5个周期(SlopeSetTime =100ms)均判定信号斜率失效,应置信号斜率故障SlopeFlt=1。
测试用例设计如下:
表2 测试用例输入表
序号 |
用例注入时刻 |
信号采集值 |
1 |
0s |
200 |
2 |
0.02s |
200 |
3 |
0.04s |
210 |
4 |
0.06s |
220 |
5 |
0.08s |
230 |
6 |
0.10s |
240 |
7 |
0.12s |
250 |
8 |
0.14s |
260 |
9 |
0.16s |
270 |
10 |
0.18s |
280 |
11 |
0.20s |
290 |
12 |
0.22s |
300 |
实测结果如下:(图中T25OriCLB为工程值):
|
|
图5 错误执行结果图
经分析发现,利用定时器触发周期任务可能受外部进程等影响,引起5ms周期超时(>20ms,应<5ms),导致5ms周期采集任务与20ms信号斜率诊断任务总是交错执行,引起时序混乱,相邻20ms任务进行斜率故障诊断的工程值未按期望更新,无法产生斜率故障。
为保证仿真测试时序的正确性,在VS2010平台上使用C语言编程重新构建软件部件仿真测试平台。其中被测软件部件以开源的形式与测试平台集成为一个完整的解决方案(.sln/.prj),以纯计数循环调度(每次循环等价于5ms)代替定时循环调度,经编译链接生成可执行文件(.exe),直接运行即可启动部件测试的执行,结果在0.12s时SlopeFlt = 1,正确产生了斜率故障,结果如下:
|
|
图6 正确执行结果图
本文提出的软件部件仿真测试平台方案,以循环调度的形式简化了对周期性运行部件的定时调度,同时保证了部件调度时序的正确性;将输入与输出进行了准确的同步;支持部件单次调度执行的性能测试;提供了四种可选的自动化执行模式。
后续研究中,将进一步增强部件仿真测试平台对部件接口的可扩展性,消除部件升级时对平台软件的直接修改,保持测试平台的稳定性;同时,逐步增加测试结果的自动判读功能,提高部件测试自动化程度。
参 考 文 献
[1] Li Hui, Shi Xiaohua, Lin Kejun, Yao Xuemei. Research on embedded software test environment platform technology for engineering equipment[J]. Computer Measurement & Control, 2016, 24(4):10-12,44(in Chinese). [黎晖,石小华,林柯军,姚雪梅.工程装备嵌入式软件测试环境平台技术研究[J]. 计算机测量与控制, 2016, 24(4):10-12,44.]
[2] Wang Qianyu, Zhu Xiaodong, Wang Yigang, Zhou Peng. Research on Real-Time Task Schedule of Embedded Software Simulation Test Environment[J]. Computer Measurement & Control, 2012,20(5):1162-1165(in Chinese). [王乾宇,朱小冬,王毅刚,周鹏.嵌入式软件仿真测试环境实时任务调度的研究[J].计算机测量与控制,2012,20(5):1162-1165.]
[3] Xia Jiajia, Zou Yijun, Zhou Jiangwei, Wang Tianmin, Cao Shengli. Research on Automatic Test Platform for Embedded Software[J]. Computer Measurement & Control, 2016, 24(4):22-25 (in Chinese). [夏佳佳,邹毅军,周江伟,王天民,曹胜莉.嵌入式软件自动化测试系统研究[J].计算机测量与控制, 2016, 24(4):22-25.]
[4] Cen Bowen, Chen Bangxing, Wan Yongbing, Jin Qingqing. Research on simulation and test platform of train control system temporary speed restriction server[J]. Computer engineering and design, 2012,33(01):372-376 (in Chinese). [岑博文,陈邦兴,万勇兵,靳庆庆.列控系统临时限速服务器仿真测试平台研究[J].计算机工程与设计,2012,33(01):372-376.]
[5] Liu Hui, Jin Maozhong. Embedded software testing technology based on all-digital simulation[J]. Journal of Beijing University of Aeronautics and Astronautics, 2014, 40(3):394-400 (in Chinese). [刘辉,金茂忠.基于全数字仿真的嵌入式软件测试技术[J].北京航空航天大学学报, 2014, 40(3):394-400.]
[6] Liu Fei. Clock-Driven-Based Cyclic Executive Scheduling[J]. Aeronautical Computing Technique, 2016, 36 (6):125-129 (in Chinese). [刘飞.基于时钟驱动的循环调度[J].航空计算技术,2016, 36 (6):125-129.]
[7] Liu Xiaoxian, Zhao Rongcai, Ding Rui. Extension to OpenMP Task Scheduling Mechanism for DSWP Parallelization and its Implementation[J]. Computer Science, 2013, 40(9):38-43 (in Chinese). [刘晓娴,赵荣彩,丁锐.面向DSWP并行的OpenMP任务调度机制的扩展与实现[J] .计算机科学, 2013, 40(9):38-43.]
[8] Dong Yong, Chen Juan, Yang Xuejun. Improved energy-optimal OpenMP static scheduling algorithm[J]. Journal of Software, 2011, 22(9):2235−2247 (in Chinese). [董 勇, 陈 娟, 杨学军.改进的能量最优OpenMP 静态调度算法[J]. 软件学报,2011, 22(9):2235−2247.]
[9] Liu Shengfei, Zhang Yunquan, Sun Xiangzheng. An Improved Guided Loop Scheduling Algorithm for OpenMP[J]. Journal of Computer Research and Development, 2010, 47(4):687-694 (in Chinese). [刘胜飞, 张云泉, 孙相征.一种改进的OpenMP 指导调度策略研究. 计算机研究与发展, 2010, 47(4):687-694.]
[10] Wang Guibin, Yang Xuejun, Xu Xinhai, Lin Yisong, Li Xin. Power-Aware parallel loop scheduling method for heterogeneous system[J]. Journal of Software, 2011, 22(9):2222−2234 (in Chinese). [王桂彬, 杨学军, 徐新海, 林一松, 李 鑫. 异构系统功耗感知的并行循环调度方法[J]. 软件学报, 2011, 22(9):2222−2234.]
[11] Jiang Yi, Nie Luyu, Mobile messaging push policy based on dynamic weights priority queue[J]. Computer engineering and design, 2013, 34(10):3520-3524 (in Chinese). [蒋溢,聂路雨.基于动态权值优先级队列的移动消息推送策略.计算机工程与设计, 2013, 34(10):3520-3524.]