本发明所要解决的技术问题在于提供一种软件单元测试自动化系统及其 方法,克服
现有技术中存在的实现测试时需要手工添加和删除代码,自动化程 度低,回归测试差,异常模拟能
力低,支持单一语言问题和缺陷,提供一种支 持多语言的软件单元测试自动化的系统和方法,很方便地支持回归测试。
为了实现上述目的,本发明提供了一种软件单元测试自动化系统,包括有
测试脚本文件;
脚本解释模
块,用于分析测试脚本文件;
测试设置模块,用于对测试单元进行测试设置;
脚本生成模块,用于把测试设置作为测试脚本保存到文件中;
测试结果输出模块,用于把测试结果和
覆盖率统计,保存到文件中或界面 显示;
其特点在于,还包括:
环境设置模块,用于让用户设置运行环境信息;
多语言支持模块,用于在用户打开测试源文件时,对源文件的编程语言类 型进行判断,调用相应的编译器对源文件进行编译生成目标文件;
目标文件分析模块,用于对目标文件进行分析;
二进制测试代码生成模块,用于根据测试脚本设置插入相应指令,产生单 元测试二进制代码;
测试代码执行模块,用于运行根据所产生的单元测试二进制代码创建的测 试线程;
测试结果判断模块,用于根据输出结果和判断条件,判断测试是否通过。
为了实现上述目的,本发明还提供了一种软件单元测试自动化的方法,其 特点在于,包括如下步骤:
步骤一,环境设置模块在该软件单元测试自动化系统中进行环境设置;
步骤二,打开要进行单元测试的源文件;
步骤三,多语言支持模块对源文件分析,确定编程语言类型,选择相应编 译器对源文件编译生成目标文件;
步骤四,没有测试脚本时,用户可以先选择对测试单元进行测试设置,测 试设置模块根据用户的设置保存到内存中,脚本生成模块把设置作为测试脚本 保存到文件中;
步骤五,用户打开测试脚本文件,脚本解释模块分析测试脚本,从中读出 与单元测试有关的信息;
步骤六,目标文件分析模块对目标文件进行分析,提出与单元测试有关的 信息;
步骤七,比较测试脚本中分析出来的信息和目标文件中分析出来的信息是 否一致,如果比较不通过则报告出错;
步骤八,二进制测试代码生成模块依据测试设置,自动插入相应指令,生 成最终的二进制测试代码。
步骤九,该软件单元测试自动化系统根据所生成的二进制测试代码创建一 测试线程,线程入口地址是测试代码执行模块,运行该测试线程;
步骤十,创建线程运行结束后,测试结果输出模块把输出结果和覆盖率统 计保存到文件中,同时显示在界面上;
步骤十一,测试结果判断模块根据输出结果和判断条件,判断测试是否通 过。
上述的方法,其特点在于,在步骤一中,该环境设置模块设置运行环境信 息的过程包括:
指定编译时需要的头文件的路径、资源文件路径、编译生成目 标文件的存放
位置、以及用户需要编译时增加的选项。
上述的方法,其特点在于,在步骤四中,该测试设置模块对测试单元进行 测试设置的过程至少包括:测试单元的入参值设置、变量的值设置、桩函数设 置、覆盖率设置、输出设置、结果判断条件;并且,该脚本生成模块是将测试 设置需要的内存信息转换成字符串信息,作为测试脚本保存。
上述的方法,其特点在于,在步骤五中,该脚本解释模块是把文本保存的 测试脚本文件从
硬盘读入后,转换成内存方式,并从中读出与单元测试有关的 信息,包括:被测单元对象、入参值设置、变量的值设置、桩函数设置、覆盖 率设置、输出设置、结果判断条件。
上述的方法,其特点在于,在步骤六中,该目标文件分析模块从目标文件 中提出与单元测试有关的信息,包括:单元信息、入参信息、变量信息、及单 元的代码信息。
上述的方法,其特点在于,在步骤八中,该二进制测试代码生成模块分析 被测单元的代码信息,依据测试设置,对函数的代码进行动态修改,自动插入 单元的运行中间变量设置指令、桩函数设置指令、覆盖率设置指令、单元运行 中间的输出设置指令,生成最终的二进制测试代码。
上述的方法,其特点在于,在步骤九中,测试执行模块把被测单元的入参 设置压入堆栈,完成最初变量的初始化,调用被测单元,完成测试线程的运行。
上述的方法,其特点在于,在步骤十中,该测试结果输出模块在单元运行 结束后,把设置中需要的信息转换成字符串,以文本文件的方式写到文件中, 显示在界面上,输出的内容包括:被测单元名称、开始测试时间、结束时间、 入参设置、全局变量设置、桩函数设置、用户设置需要输出的值、覆盖率统计 结果。
上述的方法,其特点在于,所述测试脚本文件是一以WINDOWS的INI 配置文件为格式的文本文件,可以直接通过
文本编辑器修改。
采用本发明所述系统及方法,与现有技术相比,取得了自动添加测试代码 的进步,达到了避免手工修改代码,实现回归测试,方便地实现异常模拟测试, 支持多种语言效果,节省了单元测试时间,提高了测试效率。
以下结合
附图和具体
实施例对本发明进行详细描述,但不作为对本发明的 限定。
本发明的软件单元测试自动化系统,除包括测试脚本文件、脚本解释模块、 测试设置模块、脚本生成模块、测试结果输出模块之外,还包括:环境设置模 块、多语言支持模块、目标文件分析模块、二进制测试代码生成模块、测试代 码执行模块、测试结果判断模块。要进行单元测试时,用户打开被测试单元的 源文件和测试脚本文件,多语言支持模块根据源文件确定编程语言类型,选择 相应的编译器对源文件编译生成目标OBJ文件,脚本解释模块分析测试脚本 文件,调用目标文件分析模块对编译生成的目标文件进行分析,二进制测试代 码生成模块根据测试脚本设置插入相应指令,产生单元测试二进制代码,测试 工具把生成的二进制代码创建一
进程运行,测试结果输出模块把测试结果和覆 盖率统计,保存到文件中或界面显示,测试结果判断模块自动判断测试结果是 否正常。用户可以通过测试设置模块对测试脚本进行修改,通过脚本生成模块 保存到文件中。
具体说来,本发明的软件单元测试自动化方法包括以下步骤:
第一步:通过环境设置模块进行运行环境的设置;
第二步:打开要进行单元测试的源文件;
第三步:多语言支持模块对源文件分析,确定编程语言类型,选择相应编 译器对源文件编译生成目标OBJ文件;
第四步:没有测试脚本时,用户可以先选择对测试单元进行测试设置,包 括测试单元的入参值设置,变量的值设置,桩函数设置,覆盖率设置,输出设 置,结果判断条件等,测试设置模块根据用户的设置保存到内存中,脚本生成 模块把设置保存到文件中;
第五步:用户打开测试脚本文件,脚本解释模块分析测试脚本,从中读处 被测单元对象,入参值设置,变量的值设置,桩函数设置,覆盖率设置,输出 设置,结果判断条件,测试设置模块可以在之
基础上进行修改;
第六步:目标文件分析模块对OBJ文件进行分析,提出单元信息,入参 信息,变量信息,及单元的代码信息;
第七步:比较测试脚本中分析出来的信息和目标文件中分析出来的信息是 否一致,如要测的单元在目标文件中是否存在,测试脚本中的各入参设置是否 和目标文件中相符,如果比较不通过则报告出错;
第八步:二进制测试代码生成模块分析被测单元的代码信息,依据测试设 置,自动插入单元的运行中间变量设置指令,桩函数设置指令,覆盖率设置指 令,单元运行中间的输出设置指令,生成最终的二进制测试代码;
第九步:测试工具创建一线程,线程入口地址是测试代码执行模块。在测 试执行模块中,把被测单元的入参设置压入堆栈,完成最初变量的初始化,调 用被测单元;
第十步:创建线程运行结束后,测试结果输出模块把输出结果和覆盖率统 计保存到文件中,同时显示在界面上;
第十一步:测试结果判断模块根据输出结果和判断条件,判断测试是否通 过。
下面结合附图对本发明的技术方案的实施作进一步的详细描述:
图1列出了测试脚本文件生成过程。
环境设置模块101让用户设置运行环境信息,主要是指定编译时需要的头 文件的路径,资源文件路径,编译生成目标OBJ文件的存放位置,以及用户 需要编译时增加的选项。
多语言支持模块102在用户打开测试源文件时,对源文件的编程语言类型 进行判断,调用相应的编译器对源文件进行编译。主要是以源文件名后缀判断 类型,后缀是“.c”或“.cpp”的源文件,是C语言类型,调用VC的编译器cl.exe, 后缀是“.pas”的源文件,是DELPHI类型,调用dcc32.exe编译,后缀是“.asm” 的源文件是汇编类型,调用masm的ml.exe编译,masm版本号为V6.14。采 用命令行方式调用编译器:
Cl/c/Zi/I头文件路径/Fo目标文件路径源文件名
Dcc32-J-I头文件路径-R资源文件路径-O目标文件路径源文件名
Ml/coff/c/Zd/Zi/I头文件路径/Fo目标文件路径源文件名
目标文件分析模块103对编译器生成的OBJ文件进行分析,不同的编译 器产生的OBJ文件格式不一样,需要调用不同的
算法进行分析。分析的主要 的目的是从OBJ文件中得到源文件中包含的全局变量,函数,各个函数的入 参信息,包括入参个数及入参数据类型,各个函数的局部变量信息,各个函数 的代码信息,及其在覆盖率统计需要的代码和源文件行号的对应信息。实现该 模块的关键技术在于OBJ文件的格式,VC编译器CL.EXE生成的OBJ文件 是COFF(Common Object File Format)格式,在头文件WINNT.H中有定义。 DELPHI编译器DCC32.EXE生成的OBJ格式,可以用DELPHI下的自带的 TDUMP.EXE进行分解。MASM编译器ML.EXE生成的OBJ文件时,输入选 项“/coff”,强制生成COFF格式的OBJ格式。
在目标文件分析模块对OBJ文件分析后产生的信息后,测试设置模块104 显示出函数名列表,用户选择函数后,进行设置操作:测试名称,测试时长, 如果该函数有入参,则让用户对入参进行设置,主要是对入参进行赋值,对入 参赋值时要考虑到入参的正常范围值,边界值,非法值,函数入参的正常值肯 定有,边界值和异常值不一定有,但测试时三种情况必须考虑,否则代码健壮 性有问题;用户根据测试需要对全局变量进行初始化;桩函数设置,列出该函 数调用其它函数名的列表,用户选择需要设置为桩函数的函数名,通过桩函数 设置实现测试单元与其它单元的隔离,也可通过桩函数设置指定桩函数返回值 实现一些异常测试;覆盖率设置,用户指定需要进行覆盖率统计的代码范围; 输出设置,用户指定运行结束后需要保存到文件中和显示在界面上的变量,可 以是全局变量,局部变量,函数输出参数,函数返回值;测试结果判断设置用 户指定输出设置中的变量值的范围。
在测试设置完毕后,通过脚本生成模块105把测试设置需要的内存信息转 换成字符串信息,作为测试脚本保存到文件中,供回归测试使用。
测试脚本文件106是一以WINDOWS的INI配置文件为格式的文本文件, 可以直接通过文本编辑器修改。
图2列出了本发明的单元测试过程。
脚本解释模块201,把文本保存的测试脚本文件从硬盘读入后,转换成内 存方式,这一点和脚本生成模块实现刚好相反。另外脚本解释模块还要进行必 要检查,如脚本中的函数在打开的源文件中是否存在,函数的入参是否和源文 件中一致,需要初始化的全局变量是否在源文件中存在,类型是否一致,需要 输出的信息与源文件中是否相符,桩函数设置中与源文件中相符。
二进制测试代码生成模块202是本发明的核心模块,在图3中对其流程作 了说明。主要功能是根据设置对函数的代码进行动态修改,增加或修改相应指 令,修改时及时调整代码中的跳转地址和调用地址,注意原先的短跳转指令调 整地址后如果跳转地址超过128字节,需要变成长跳转指令。开始需要申请三 块内存,pCodeBuf用于存放新代码,长度为原代码长度的2倍,在以后添加 代码过程中如果空间不够,需要及时重新申请,pDataBuf用于存放设置测试 输出的信息,长度为所有输出信息的长度和,pCoverBuf用于存放覆盖率信息, 长度为原代码长度。单元运行中变量设置,对指定变量进行赋值。单元运行中 变量输出设置,把指定变量的值输出到指定内存区域。桩函数设置,把调用函 数的位置用空指令代替,并根据用户设置对寄存器EAX,EDX赋值,作为桩函 数的返回值。覆盖率设置,作代码分支覆盖率统计,对申请到的内存pCoverBuf 清0,对整个被测单元的代码反汇编,在跳转指令后和跳转目标地址插入覆盖 率统计指令,插入的指令实现对申请到的内存相应位置置1操作,注意需要保 护插入指令中使用到的寄存器原先的值,如下所示,变量iCoverOff为内存偏 移:
push esi
mov esi,pCoverBuf
mov[esi+iCoverOff],1
pop esi
iCoverOff加1
在覆盖率统计时如果内存中值为1表明相应的分支得到运行,与在目标文 件分析模块得出的代码和源文件行号的对应信息相结合,这样可以统计出被测 单元的覆盖率。
测试代码执行模块203,是测试线程的入口。首先入参设置,对应普通变 量的入参,直接把值压入堆栈,对
指针类型,需要对指针指向的内容设置的入 参,先按照指针父类型的大小申请一块内存,把申请到内存的地址压入堆栈, 再把内存按照指针父类型转换后,对各个字段赋值。其次全局变量设置,按照 设置修改全局变量内存的值。最后调用二进制测试代码生成模块产生的测试代 码。
测试结果输出模块204,在单元运行结束后,把设置中需要的信息转换成 字符串,以文本文件的方式写到文件中,显示在界面上。输出内容包括:被测 单元名称,开始测试时间,结束时问,入参设置,全局变量设置,桩函数设置, 用户设置需要输出的值,覆盖率统计结果。
测试结果判断模块205,对测试结果判断设置进行简单的编译,根据测试 结果判断设置,取出对应的变量值判断是否在用户的设置范围内,可以得出本 次测试结果是否正常,显示在界面上。
至此,单元测试结束,释放在测试中申请的内存。
在整个单元测试过程中,输入被测单元代码后,不需要手工修改任何代码, 自动实现入参输入,全局变量初始化,变量观察输出,桩函数设置,覆盖率统 计,真正实现自动化测试,能很好地支持回归测试,节省测试时间,提高效率。 通过单元运行中设置变量模拟异常情况,增加分支覆盖率。
本发明的方法已在实验中被证实可行。
以下是本发明方法的具体举例:
所需被测单元用C语言的编写。
int test(int InPara)
{
if(InPara)
retum 1;
else
return 0;
}
测试设置后,测试脚本如下:
[测试
用例0]
用例名称=test
运行次数=1
函数运行时长(秒)=1
函数0=test()
函数0_入参0_InPara=1
函数0_输出0=返回值
判断规则=((函数0_入参0_nPara!=0)&&(函数0_输出0!=0)
||(函数0_入参0_InPara==0)&&(函数0_输出0==0))
多语言支持模块编译生成OBJ文件,函数代码反汇编如下:
push ebp
mov ebp,esp
cmp dword ptr[ebp+0x08],0x00
jz RET_ZERO
mov eax,0x00000001
pop ebp
ret 0x04
RET_ZERO:
xor eax,eax
pop ebp
ret 0x04
经过二进制测试代码生成模块运行后,最终测试代码如下:
push ebp
mov ebp,esp
;插入覆盖率统计0
push esi
mov esi,pCoverBuf
mov[esi],1
pop esi
cmp dword ptr[ebp+0x08],0x00
jz RET_ZERO1
;插入覆盖率统计1
push esi
mov esi,pCoverBuf
mov[esi+1],1
pop esi
mov eax,0x00000001
pop ebp
ret 0x04
RET_ZERO1:
;插入覆盖率统计2
push esi
mov esi,pCoverBuf
mov[esi+2],1
pop esi
xor eax,eax
pop ebp
ret 0x04
测试代码执行模块,把入参InPara的设置值1压入堆栈,把pCodeBuf作 为函数地址调用。被测单元test的返回结果,在测试代码执行模块中把寄存器 eax的值放入pDataBuf中,如下:
push esi
mov esi,pDataBuf
mov[esi],eax
pop esi
测试结果输出模块和测试结果判断模块,在取函数返回值时,直接从 pDataBuf中取,保证数据可靠性。
从上面简单的例子可以看出,在整个测试过程中,不需要手工对测试代码 进行任何修改,即可自动实现入参的输入,函数返回值的输出,覆盖率统计实 现,及其测试结果的判断。真正实现单元测试自动化。
当然,本发明还可有其他多种实施例,在不背离本发明精神及其实质的情 况下,熟悉本领域的技术人员当可根据本发明作出各种相应的改变和
变形,但 这些相应的改变和变形都应属于本发明所附的
权利要求的保护范围。