CN104731695B - 一种支持表格驱动底层输入的单元测试系统和方法 - Google Patents

一种支持表格驱动底层输入的单元测试系统和方法 Download PDF

Info

Publication number
CN104731695B
CN104731695B CN201310703548.8A CN201310703548A CN104731695B CN 104731695 B CN104731695 B CN 104731695B CN 201310703548 A CN201310703548 A CN 201310703548A CN 104731695 B CN104731695 B CN 104731695B
Authority
CN
China
Prior art keywords
function
variable
code
input
type
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Active
Application number
CN201310703548.8A
Other languages
English (en)
Other versions
CN104731695A (zh
Inventor
不公告发明人
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Guangzhou Kaile Software Technology Co Ltd
Original Assignee
Guangzhou Kaile Software Technology Co Ltd
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Guangzhou Kaile Software Technology Co Ltd filed Critical Guangzhou Kaile Software Technology Co Ltd
Priority to CN201310703548.8A priority Critical patent/CN104731695B/zh
Publication of CN104731695A publication Critical patent/CN104731695A/zh
Application granted granted Critical
Publication of CN104731695B publication Critical patent/CN104731695B/zh
Active legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Abstract

本发明公开了一种支持表格驱动底层输入的单元测试系统和方法,包括:类型解析装置,用于解析数据类型定义获得类型信息;树表装置,由树形控件和表格控件组成;赋值装置,用于将树表装置中的输入值赋给变量;底层变量设定装置,用于供用户指定底层变量并加入树表;底层输入设置装置,用于查询用户设置的底层变量,及调用赋值装置和/或让底层函数继续执行;函数调用拦截装置,用于拦截底层函数的调用,并调用底层输入设置装置。本发明使底层输入由表格驱动,即完全由表格来控制底层输入,简化了测试数据的管理和维护,提升了测试数据的可重用性。本发明解决了函数的调用耦合形成的单元测试障碍,使单元测试的效率大幅度提升。

Description

一种支持表格驱动底层输入的单元测试系统和方法
技术领域
本发明涉及软件测试技术,特别是涉及软件单元测试技术。
背景技术
单元测试是软件开发过程中保证代码质量,提升开发产能的重要手段。
单元测试的基本方法是利用测试驱动代码,设定输入和预期输出,执行被测试程序,自动判断实际输出是否符合预期。输入数据和预期输出称为测试用例,也就是测试数据,这是单元测试工作的基本要素,而对输入的赋值过程和判断输出的比较过程,则是单元测试执行过程的核心。
实施单元测试的一个主要障碍是底层输入问题。底层输入,就是调用底层函数获得的输入。底层函数,就是被测试函数所调用的关联函数。
例如下面的C++语言代码:
功能:空调控制程序片断,取得环境温度并计算制冷器需运行的时间
参数:pWorkTime,输出参数,保存制冷器需运行的时间
返回:int类型,如果函数执行失败,返回0,否则返回非0值
WorkTime()是被测试函数,功能是取得环境温度并计算制冷器需运行的时间,取环境温度的方式是调用函数GetTemperature(),GetTemperature()通过调用硬件温度计来获得环境温度。在这里,GetTemperature()就是被测试函数调用的关联函数,即底层函数。被测试函数和底层函数存在调用耦合关系,给单元测试造成了困难。如何界定调用耦合关系形成的对单元测试的影响,才更易理解和化解影响呢?本质上来说,底层函数GetTemperature()的输出,也是被测试函数的一种输入形式,与通过参数传递的输入并无本质区别。例如,把被测试函数改为:
即原来通过调用GetTemperature()取得的数据,通过参数传递进来,代码的功能逻辑和计算结果是完全一样的。所以,通过调用底层函数取得的数据,这些数据对底层函数来说,是输出,但对于被测试函数来说,跟参数一样,也是一种输入,称为底层输入。
对于如何控制通过调用底层函数取得的数据,有多种方法,例如,编写桩代码,让底层函数产生各种输出,或者,通过Mock Object,即用模拟对象来代替实际的对象。这些方法,都比较麻烦,通常需要编写或修改大量的代码,例如,要让GetTemperature()的桩代码在五个用例中输出五种温度,需要在桩代码中判断是哪个用例在调用并输出对应的数据,大约需要15行代码,如果GetTemperature()函数还可能被更多的被测试函数调用,那么,桩代码中还要判断是哪个被测试函数在调用,工具通常只能生成桩的简单实现而无法自动生成各用例所需要的输出数据,编写桩代码的工作量是巨大的。另一方面,桩或模拟对象产生的数据,与参数等其他数据通常无法放置在一起,造成一个被测试函数的用例数据,存放在多处,难于维护。另外,对于底层函数,有时要直接调用实际代码,有时要调用桩或MockObject,这种控制和切换过程也增加了工作量。
底层输入这一概念,将通过调用底层函数取得的数据与参数等方式输入的普通数据同等看待。更重要的是,如果不需要编写桩代码或Mock Object,可以做到直接设置底层输入,并且与参数等输入放在一起管理,那么,单元测试的工作量将大为降低。特别是,如果底层输入可以通过表格来驱动,即由表格来决定需要哪些底层输入以及底层输入的值,针对复合类型,由表格来决定哪些成员需要设置底层输入,哪些成员不需要设置底层输入,具体来说,实现如下功能,那么,将大幅提升单元测试工作的效率:
a.如果用户未在表格中设置底层输入,则调用实际代码;
b.如果用户在表格中设置了底层输入,则将底层输入赋给对应的变量,实现对底层输入的设置;
c.表格支持任意类型,即复合类型的底层输入也可以直接在表格中设置,由表格来决定哪个成员需要设置底层输入;
d.无论底层函数是否存在、是否被隔离,都可以通过表格设置底层输入,用户无需额外设置。
这样,用户不需要另外去控制底层函数是否调用实际代码,并且可以像参数一样,直接设置底层输入,那么,函数的调用耦合就不再是单元测试的障碍,单元测试的效率可以大幅度提高。
已经有个别单元测试工具实现了基本类型数据的表格化,也实现了对底层输入的设置,底层输入也可以移到表格中,例如广州凯乐软件技术有限公司于2013年3月份发布的单元测试工具Visual Unit3.0,具有底层模拟功能,但存在重要的缺陷:
a.需要额外的测试驱动代码,Visual Unit3.0的底层模拟的工作方式是:在测试驱动代码中添加底层模拟代码,在用例执行时,底层模拟代码将用户设定的底层输入数据保存到内存,在调用底层函数时,通过查询这些数据来决定是否设置底层输入;
b.手动将数据移到表格中;
c.不能将复合类型、数组、控指针等底层输入直接放在表格中,对于复合类型的底层输入,需要先编写代码,将复合类型分解为基本类型,再将基本类型的数据移到表格中,这导致在面对复杂类型时,可能需要编写和维护额外的大量测试驱动代码;
d.对底层输入的赋值过程,采用内存整体浅拷贝方式,当面对复杂的对象时,如复杂的C++对象,变量的赋值结果可能是不正确的,并且也无法满足只对复合变量的某些成员设置底层输入的需求;
e.由于是否设置底层输入是由测试驱动代码来实现的,因此,实质上是测试代码驱动,并不是真正的表格驱动,当测试驱动代码中存在了底层模拟代码,则无论表格中是否设置了值,都会造成对底层函数的模拟,这样,数据表格中的多个用例无法控制底函数是否调用实际代码,即无法做到表格中的一些用例设置底层输入,一些用例调用实际代码。
综上所述,现有技术对于底层输入并不是真正的表格驱动,而是使用额外的测试驱动代码来驱动,尤其是针对复合类型时,额外的测试驱动代码数量可能很多,增加了调试和维护测试驱动代码的成本,需要手动将数据移到表格中,数据表格不支持复合数型的底层输入,并且底层输入的内存拷贝赋值方式导致变量的赋值结果可能是不正确的,也不能满足只设置部分成员或只设置部分用例的需求。
发明内容
本发明要解决的技术问题是,提供一种真正支持表格驱动底层输入的单元测试系统和方法,消除前述的现有技术的缺陷。为了解决上述技术问题,本发明提出的技术方案是:
一种支持表格驱动底层输入的单元测试系统,包括测试驱动代码,其特征在于,包括:
A:类型解析装置,用于解析数据类型定义获得类型信息;
B:树表装置,由树形控件和表格控件组成,用于树状显示变量及其成员,并提供表格供用户填写测试用例的输入值;
C:赋值装置,用于将所述树表装置中的所述输入值赋给变量,所述变量的数据类型包括基本类型和复合类型;
D:底层变量设定装置,用于供用户指定底层函数的底层变量,并将所述底层变量加入装置B,所述底层函数,是指被测试函数调用的函数,所述底层变量包括以下变量之一或以下变量的任意组合:
所述底层函数的返回值、所述底层函数的输出参数、所述底层函数改写的成员变量、所述底层函数改写的全局变量,
所述底层变量的数据类型包括基本类型和复合类型;
E:底层输入设置装置,用于查询用户在装置B中是否设置了所述底层变量,及调用装置C和/或让所述底层函数继续执行;
F:函数调用拦截装置,用于拦截所述底层函数的调用,并调用装置E。
装置D所述的底层变量还可以进一步包括:用于控制所述底层函数是否直接跳过的变量、所述底层函数的被调用次数,装置B所述的表格还可以进一步包括:供用户填写测试用例的输出值的单元格。
一种支持表格驱动底层输入的单元测试方法,包括测试驱动代码,其特征在于,包括:
A:类型解析步骤,用于解析数据类型定义获得类型信息;
B:树表步骤,所述树表由树形控件和表格控件组成,用于树状显示变量及其成员,并提供表格供用户填写测试用例的输入值;
C:赋值步骤,用于将所述树表中的所述输入值赋给变量,所述变量的数据类型包括基本类型和复合类型;
D:底层变量设定步骤,用于供用户指定底层函数的底层变量,并将所述底层变量加入所述树表,所述底层函数,是指被测试函数调用的函数,所述底层变量包括以下变量之一或以下变量的任意组合:
所述底层函数的返回值、所述底层函数的输出参数、所述底层函数改写的成员变量、所述底层函数改写的全局变量,
所述底层变量的数据类型包括基本类型和复合类型;
E:底层输入设置步骤,用于查询用户在所述树表中是否设置了所述底层变量,及调用步骤C和/或让所述底层函数继续执行;
F:函数调用拦截步骤,用于拦截所述底层函数的调用。
另外,本发明还提出了前述支持表格驱动底层输入的单元测试系统的次佳方案,其特征在于,用特征G代替特征B:
G:表格装置,用于供用户填写测试用例的输入值。
装置D所述的底层变量,即为前述的底层输入。本发明实现了表格驱动底层输入的单元测试系统,对于底层输入的设置,不需要额外的测试驱动代码;不需要手动将数据移到表格中;数据表格直接支持复合数据类型的底层输入;支持只对变量的部分成员设定底层输入;支持只对表格中的部分用例设置底层输入;解决现有技术的底层输入变量的赋值结果可能不正确的问题。本发明完全克服了现有技术的主要缺陷。对于利用本发明开发的单元测试工具,用户不需要编写和维护一行代码,仅通过表格中的数据,就可以随意控制底层函数的行为,例如,用例1调用实际代码,用例2直接设置需要的底层输入,或者任意对复合类型的成员设置或不设置底层输入,即底层输入完全由表格决定,实现了意正的表格驱动,即完全由表格来控制底层输入,简化了测试数据的管理和维护,提升了测试数据的可重用性。对于支持表格驱动的单元测试工具来说,底层输入与参数等其他输入在同一表格中管理,不存在一个函数的测试数据多处存放的问题。利用本发明,函数的调用耦合就不再是单元测试的障碍,单元测试的效率可以大幅度提高。
本发明除了解决底层输入的表格驱动问题,还可以解决对底层函数的执行控制与判断问题:使用所述用于控制所述底层函数是否直接跳过的变量,可以使底函数不执行也不设置底层输入直接跳过,以便解决有些底层函数在测试执行过程中崩溃导致测试中断的问题;所述底层函数的被调用次数,则是对底层函数是否执行及执行次数的判断,可用于对执行流程的判断,在通讯、自控等领域具有广泛的应用价值。
附图说明
下面结合附图对本发明的具体实施方式作进一步详细的说明:
图1是本发明的一个实施例的总体构成示意图;
图2是一些示例数据类型的定义;
图3是使用了图2所示的数据类型的一个示例被测试函数;
图4是图1所示的装置102的应用效果示意图;
图5图1所示的装置104的应用效果示意图;
图6图7图8是本发明的应用效果与现有技术的比较示意图,其中:
图6是一个被测试函数和底层函数的示例代码;
图7是现有技术与应用本发明后的测试驱动代码对比示意图,其中,图7A是现有技术的测试驱动代码,图7B是应用本发明后的测试驱动代码;
图8是现有技术与应用本发明后的表格数据示意图,其中,图8A是现有技术的表格数据,图8B是应用本发明后的表格数据。
具体实施方式
图1是本发明的一个实施例的总体构成示意图,如图1所示,本实施例包括下述装置:类型解析装置101;树表装置102;赋值装置103;底层变量设定装置104;底层输入设置装置105;函数调用拦截装置106。
本发明的示例代码采用C语言或C++语言编写,但不代表本发明只适用于C语言和C++语言。本发明所列举的示例代码仅仅为了便以说明本发明的技术方案,不代表是对本发明的限制。
装置101解析数据类型定义获得类型信息。类型信息属于本领域的通用术语,不同的编程语言,类型信息可能有些差别,一般来说,类型信息包括:类型名称、内存大小,各成员的成员名称、类型名称、偏移量,当然,还可以包含其他信息,如成员函数列表。下面是用于描述类型信息的数据结构的一个示例:
用于描述一个成员,其中:type为成员的类型;name为成员的名称;offset为成员的偏移量。
用于描述一个类型,其中,type为类型名称,size为类型的实例的内存大小,childCount为成员数量,pChilds为成员指针数组。当用于基本类型时,childCount为0,pChilds为NULL。当然,也可以不使用childCount和pChilds,而是使用一个链表或类似的集合来代替。
装置101扫描被测试代码,对各个数据类型的定义进行解析,获得类型信息,可以将类型信息保存在映射表中,供本发明的其他装置查询使用。由于解析过程属于一般的代码解析和编译技术,这里不作更详细的说明。
装置102是一个树表,由树形控件和表格控件组成,用于树状显示变量及其成员,并提供表格供用户填写测试用例的输入值和输出值,在本发明的基本实施方案中,树表可以不提供填写输出值的功能,但如果底层变量包括底层函数的被调用次数,这是用来判断底层函数是否被调用及调用次数的变量,属于用例的输出值,则树表需要提供填写输出值的单元格,为了便以说明,后文中树表均使用包括输出值的方式。树表既可以像一般的树形控件一样,展开到每个叶子结点,或收起一些结点只显示部分结点,也可以像一般的表格控件一样增加不限数量的列,以便填写不限数量的用例。
图2图3图4示出了装置102的应用效果,其中,图2是一些示例数据类型的定义,图3是使用了图2所示的数据类型的一个被测试函数,图4是装置102的应用效果示意图,即针对图3所示的函数,供用户建立测试数据的界面示意图。用户可以选择单元格设置输入和输出值,也可以增加列来建立更多的用例。
对于每一个变量,根据变量的类型查询装置101所获得的类型信息,将该变量加入树表,并递归扫描所有的成员,根据成员的类型名称找到类型信息,将成员作为子结点加入树表,直到基本类型,即树表的子结点均为基本类型,为了方便用户查看各结点的成员及类型,树表的结点可以显示变量名称和类型名称,也可以将对应的类型信息如前述DataType结构的指针保存在结点中,方便后续的操作。表格部分,可以采用一行两列方式,即每个结点对应表格部分的一行,每个用例两列,即输入列和输出列,也可以使用一列两行方式,即每个节点对应表格部分的两行,即输入行和输出行,每个用例占用一列。在后文中引述装置102时,均采用一行两列方式。用户可以通过增加列来建立更多的用例。至于树表控件的实现过程,和将变量加入树表的过程,以及对树表的常规操作过程,属于现有技术,这里不作详述。
装置103将树表装置中的输入值赋给变量,变量的数据类型可以是基本类型,也可以是复合类型,即装置103用于将基本类型或复合类型的数据,为基本类型或复合类型的变量赋值。由于树表本身是根据变量及其成员的树形关系建立的,树表中的数据,与变量及其成员具有一一对应的关系,装置103的实现思路就是根据这种关系进行赋值操作,在总的思路下,可以设计出多种具有不同细节的实现过程。
下面示出一种实现过程,其具体的思路是:递归扫描变量及其成员,对需要初始化的变量或成员初始化,对于对应输入值不为空的变量或成员,拷贝对应输入值;所述对应输入值,是指所述树表装置中,变量或成员对应的当前用例的输入值,例如,树表采用一行两列方式,则对应输入值是指变量或成员对应的行和当前用例的输入列组成的单元格的值,有些对应输入值可能需要经过转换,例如,整数类型,表格中填写的可能是字符串,要转换为整数。例如,针对C或C++语言,下面的步骤可以实现装置103:
1)根据变量的类型名称,可以找到对应的类型信息,以及是否为指针或数组。数组可以视为复合类型,如int[10],可以视为含有10个int类型成员的复合类型。
2)将变量设为空值,例如C语言,对于指针,则设为空指针,非指针则调用memset()清空内存。如果变量对应输入值为空,且所有直接和间接成员的对应输入值也为空,则返回。
3)如果变量的类型为指针,且对应输入值为空指针,则设为空指针。返回。
4)变量如果需要自行管理内存,如C或C++的指针,则先申请内存。申请内存的方式视语言而定,如C语言,可以调用malloc(size),而对于C++,则调用new操作符。
5)将对应输入值拷贝到变量的内存中,例如C语言,可以用以下方式拷贝:
字符串:strcpy(pDes,pSrc),其中,pDes为变量或成员的指针,pSrc为对应输入值。
整数int:*((int*)pvar)=value,其中,pvar为变量或成员的指针,value为对应输入值。
其他类型的拷贝方式大同小异,不再一一列举。
6)针对变量的每一个成员,根据成员的偏移量,计算出成员的指针,并递归执行上述步骤。
步骤2)3)4)可以看作是对变量或成员初始化。对变量或成员初始化是本领域的基础技术,不同的编程语言,不同的类型,初始化的过程可能不同。对于不使用指针的语言,不需要申请内存和设置空指针的步骤,这种情形下,对变量或成员的内存初始化,通常只是将内存清空或设为缺省值。
有些语言的有些变量的初始化,可能需要调用构造函数,例如C++语言的含有虚函数的类型,其对象的初始化,最好调用构造函数,以免由于虚函数表不正确影响测试执行过程,这种情形下,可以用下述方法代替步骤4)所述的new操作符:在解析类型信息时建立一个需调用构造函数的类型的列表,并给每个类型分配一个序号,并生成对象生成函数的代码,测试代码开始执行时,将对象生成函数的指针传递给测试工具,对象生成函数的功能是根据类型序号调用类型的构造函数生成对象指针,在对变量初始化时,调用对象生成函数并传递类型编号,从而得到调用构造函数而建立的对象指针。对于支持运行期构造对象的语言,如Java语言,不需要使用这种方式。
前述步骤的对变量的初始化,未考虑部分赋值的情形,即只对底层变量的部分成员赋值的情形。对于需要部分赋值的底层变量,需要对初始化过程作出修改,例如,对于复合类型的底层变量,只对具有对应输入值的变量或成员进行初始化,其他变量或成员不需要初始化,以便使其他成员保持原有值。
可以针对表格数据制定一些规则,例如,对于某些特殊的值,可以约定表示该值的符号,如用NULL表示空指针,本发明的示例中,在树表或表格中,均使用NULL表示空指针。
为了实现上的简便,在上述步骤5),通常只处理基本类型,如果树表允许直接针对复合类型填写复合数据,则这种数据通常是按某些规则编排的数据,如图4所示的单元格401中的数据,对于这种情形,在执行赋值过程前,可以将数据分解并分配到叶子结点对应的单元格,即基本类型的成员对应的单元格,以便使步骤5)只处理基本类型。
装置104用于供用户指定底层函数的底层变量,并将底层变量加入装置102,底层函数,是指被测试函数调用的函数,底层变量,是指调用底层函数所输出的变量或用于控制或判断底层函数执行的变量,包括:底层函数的返回值、底层函数的输出参数、底层函数改写的成员变量、底层函数改写的全局变量、用于控制底层函数是否直接跳过的变量、用于判断底层函数被调用次数的变量,其中,前四项属于底层函数的输出,对于被测试函数来说,则是输入,即底层输入,应用本发明时,可以选择支持这些变量之一或这些变量的任意组合,后两项用于对底层函数控制或判断。底层变量的数据类型包括基本类型和复合类型。对于底层函数不应该改写的数据,例如输入参数或传值参数、底层函数不改写的成员变量或全局变量,通常不需要作为底层变量,利用本发明时,将这些变量也列为底层变量也是可行的,只不过在测试上没有意义。一个底层函数,可能存在众多的输出变量,但不一定全部均作为底层变量,只有测试过程中需涉及的变量,也就是被测试函数的执行过程需要使用的变量,才需要作为底层变量。
装置104提供一个交互界面,供用户指定底层变量,并将用户指定的底层变量加入树表,一种实现方式是提供一个简单的界面,由用户填写底层函数名、底层变量的类型和名称,其中,名称可以依约定的规则设定,如return表示返回值,arg1表示第一个参数,为了便于用户识别不同的参数,对于有名参数,更佳的方式是使用原参数名。然后将用户填写的底层变量加入树表,为了便以区分底层变量与其他变量,加入树表时,可以约定命名规则,例如:func()return,表示函数func()的返回值,func()arg1,表示函数func()的第一个参数,func()gVar表示调用函数func()后,全局变量gVar的结果值。也可以将一个底层函数的底层输入组成一个树形结构,如func()作为根结点,下面有三个子结点:return,arg1,gVar。
为了进一步提升效率,装置104的更佳实现方式是:解析被测试代码获得可能的底层变量列表供用户选择,图5中更佳实现方式的一个界面示例。如图5所示,装置104自动列出可能的底层变量的类型、名称等数据供用户选择。一种实现思路是,对被测试代码进行解析,记录每个函数的返回值类型、出参及类型、可能改写的成员变量及类型、可能改写的全局变量及类型,并显示被测试函数的代码,用户在双击底层函数的被调用代码时,显示可能的底层变量及其类型,用户只需要选中要使用的底层变量,即可完成设置。
置104也可以增加让用户选择是否初始化的选项,以便对只需要部分赋值的变量,装置103的赋值过程中,对于不需要设置底层输入的成员不进行初始化,保持原值不变。
用户完成底层变量的设置后,装置104将底层变量加入树表,用户即可以在树表中针对各用例设置具体的值。
装置105用于查询用户在装置102中是否设置了底层变量,及调用装置103和/或让底层函数继续执行。装置105可以实现为一个函数,下面是该函数的一个示例的声明:
long_SubInput(const char*fn,void**prt,void*data,long count);
第一个参数传递底层函数名;第二个参数是用于保存返回值的二级指针;第三个参数是保存出参信息的数组,出参信息可以包括参数的序号,参数变量的地址;第四个参数传递出参的数量。返回值用来传递用户是否在当前用例设置了底层输入,例如,用户设置了底层输入,则返回1,否则返回0。
至于在哪些情形下允许底层函数继续执行,可以在应用中制定规则,也可以由用户选择。一般来说,一旦某个底层变量在树表中设置了值,底层函数就可以不再执行,下面按照此规则给出进一步的实现思路:
1)如果树表中没有底层函数的底层变量,返回0,底层函数继续执行;
2)如果树表中有底层函数的底层变量,则查询在当前用例下用户是否设置了值,如果该底层函数的所有底层变量均没有设置值,返回0,底层函数继续执行;
3)调用装置103将用户设置的值赋给变量,并返回1,底层函数不再执行。在调用装置103时,返回值和出参的指针已由参数传递,而成员变量和全局变量的地址,一般需要另外获得。本发明可以只支持部分底层变量,例如,只支持返回值和/或出参,如果需支持将成员变量和全局变量作为底层函数的底层变量,那么,需要添加取得全局变量的地址的步骤,例如,在测试驱动代码中添加一些代码,用于传递各全局变量的地址并保存到某个地方。对于成员变量,可以根据被测试类的类型信息、被测试对象的指针和成员变量名查询获得。对于返回值地址和各出参的地址,在说明装置106时进一步说明。
前述用于控制底层函数是否直接跳过的变量,这里称为跳出变量,用来支持直接跳过底层函数,通常用于跳过在单元测试环境下调用会产生异常的底层函数,例如,界面类的函数可能因为界面资源在单元测试环境下不存在导致执行崩溃,当这类函数产生了对测试有意义的输出时,通过设置底层变量可以跳过,否则,可以使用跳出变量来控制,跳出变量可以使用布尔、int、long等类型,前述_SubInput示例函数可以增加对跳出变量的查询,如果用户设置了跳出变量,则无论是否设置了其他底层变量均返回1,使底层函数不再执行。
前述用于判断底层函数被调用次数的变量,这里称为判断变量,用来支持对底层函数的调用次数的判断。判断变量可以使用int或long类型之类的整数类型。与其他底层变量不同,判断变量用于在被测试函数执行后,判断底层函数是否被调用及调用次数,这在测试用例中是一种预期的输出而不是输入,因此,如果使用了判断变量,装置102中需要提供填写输出值的单元格,例如,提供输出行或输出列。以下是判断变量的应用的一个实现思路:在前述_SubInput示例函数执行时,针对当前底层函数设置一个计数器,_SubInput执行一次,则当前底层函数的计数加1,在测试驱动中增加对调用次数的判断,即读取树表中用户对判断变量的设置值并与所记录的执行次数比较,如果不符合,则输出测试失败信息。由于判断变量是基本类型,比较过程属于现有技术,这里不作详述。
装置106用于拦截所述底层函数的调用,即当底层函数被调用时,不是直接执行,而是跳转到装置105。对函数调用的拦截是本领域的常用技术,是本领域技术人员可以实现的,实现的方式有多种,如:函数钩子、指令跳转、插入拦截代码、代码替换等。
函数钩子是一种有多年历史的技术,如Windows用于拦截API和消息的钩子函数,在此不作详述。
指令跳转也是常用技术,在调试工具中极为常用,例如C或C++语言开发的代码,编译后通过修改机器码的函数调用指令后的调用地址,即可实现指令跳转。对于单元测试工具来说,可以对被测试代码编译链接后产生的可执行文件进行分析,找出被测试函数对应的机器码中的对底层函数调用的指令并保存其位置、原调用地址、输出参数的地址等信息,在测试执行过程中,通过修改调用地址来实现对底层函数的拦截,调用装置105并传递返回地址和出参信息。对于使用函数钩子拦截方式,也可以用同样的方法获得调用装置105时可能需要的返回地址和出参信息。对可执行文件的分析是对编译和链接过程的反向工作,根据编译器链接器的特性和调用协议,对机器码中调用指令及调用指令前后的指令进行分析,属于现有技术,这里不作详述。
插入拦截代码是指在底层函数的入口插入代码实现拦截功能。相对于前两种方法,插入拦截代码可以实现对底层函数更为直接的控制,并由拦截代码提供调用装置105时可能需要的返回值地址和出参信息,以下是插入拦截代码的一种实现示例:
其中,结构SUB_INPUT_DATA用于保存出参序号和地址,其定义为:
函数_SubInput()是装置105的一种实现。至于如何插入拦截代码,这是一般的代码解析及代码插装技术,属于现有技术,这里不作详述。
代码替换是指将对底层函数的调用替换为对代替函数的调用,代替函数是具有调用装置105功能的代替原底层函数的函数。通常需要另外编写或由工具生成代替函数,代替函数可以用拦截代码来调用装置105,其拦截代码的实现类似于前述插入拦截代码部分的示例。代码替换的一种思路是:如果底层函数未实现或被隔离,则用与底层函数同名的函数代替底层函数;否则用与底层函数不同名的函数作为代替函数,并直接修改被测试代码或通过预编译机制间接修改被测试代码,将对底层函数的调用替换为对代替函数的调用,即常见的代码替换有两种情形:
1)原底层函数未实现或需要隔离,则代替函数还具有桩的功能,以便让测试代码能通过编译链接,这种情形下,代替函数可以实现为同名函数,即原形与原底层函数原形完全一样的函数,测试执行过程中将直接调用代替函数,被测试函数的代码不需要修改,这样既完成了打桩,又实现了调用拦截。
2)原底层函数已实现且不需要隔离,则代替函数应与底层函数不同名,在编写或生成代替函数后,手工或由工具对被测试代码进行直接修改,或利用宏语法等预编译机制,将对底层函数的调用替换为对代替函数的调用,这种情形下,代替函数一般应该调用原底层函数,以便根据用户的设置在需要时调用原底层函数。
代替函数的编写或生成,以及让测试代码调用代替函数的过程,属于现有技术,这里不作详述。
上述几种拦截方式可以单独使用,更佳的方式是综合使用,例如,对于用户定义的且未隔离的函数使用插入拦截代码方式,对于用户定义的但未实现或被隔离的函数使用代码替换方式,对于库函数,使用代码替换方式或指令跳转方式或函数钩子方式。
下面是本发明的一个实施例的具体工作过程:
装置101解析类型信息供其他装置使用。用户通过装置104,针对一个或多个底层函数,分别设置一个或多个底层变量,自动添加到装置102中。用户在装置102中对底层变量进行赋值,对于需要执行底层函数原始代码的用例,则不对底层变量赋值。测试执行过程中,当被测试代码调用底层函数时,通过装置106拦截调用并调用装置105,装置105查询树表中的底层变量及用户设定值,如果用户未设定当前用例的底层变量,则继续执行原函数,否则调用装置103进行赋值并返回。对于复合类型的底层变量,用户可以只对其中的个别成员赋值,即对底层变量部分赋值,以便保持变量的其他成员不变。
图6图7图8是本发明的应用效果与现有技术的比较示意图,其中:图6是一个被测试函数和底层函数的示例代码;图7是现有技术与应用本发明后的测试驱动代码对比示意图,其中,图7A是现有技术的测试驱动代码,图7B是应用本发明后的测试驱动代码;图8是现有技术与应用本发明后的表格数据示意图,其中,图8A是现有技术的表格数据,图8B是应用本发明后的表格数据。如图6所示,函数mysub()是底层函数,函数subinputtest()是被测试函数。如图8所示,在需要设定的底层输入数据相同或相似的前提下,如图7B所示,利用本发明,测试驱动代码不需要增加额外的代码,如图7A所示,现有技术需要添加大量的测试驱动代码,图7A中,第3至第15行共13行代码,均为底层模拟代码,其中,仅有第15行由工具生成,其他均需要手工编写,并需手工将数据移到表格中。从图7的比较可以看出,利用本发明,可以避免编写大量的用于实现底层输入的代码,仅此一项,就可以大幅提升单元测试的效率。
对于本发明所述的支持表格驱动底层输入的单元测试方法,其实现步骤已包含于前面的说明中,不再重复。
本发明可以不使用树表装置102,而用一般的表格来代替。这是一种次佳方案,也能实现本发明的主要效果,但是,使用表格方式,要么将变量及其所有直接或间接成员全部加入表格,要么只加入变量本身而不加入成员,当数据类型很复杂时,这两种方式对用户都不方便,前者造成表格中行数太多,特别是对于含有指向自身指针的成员的类型,可能造成死循环,后者则填写数据的难度较大。如果采用将变量及其所有直接或间接成员全部加入表格的方式,那么,实施本发明的过程,除装置102部分改为使用表格,其他装置的实施方式是一样的。如果采用只加入变量本身而不加入成员的方式,那么,可以将单元格中的复合数据分解为基本类型的数据,如图4所示的单元格401中的数据,可以先分解成基本类型的数据,这些分解后的数据,与变量的成员是对应的,装置103仍然可以按前述的方式进行赋值。
以上实施例仅是本发明的较佳实施方式,仅用以说明本发明而非限制,对本发明进行修改、变形或者等同替换而不脱离本发明的精神和范围,均应涵盖于本发明的范围之内。

Claims (10)

1.一种支持表格驱动底层输入的单元测试系统,包括测试驱动代码,其特征在于,包括:
A:类型解析装置,用于解析数据类型定义获得类型信息;
B:树表装置,由树形控件和表格控件组成,用于树状显示变量及其成员,并提供表格供用户填写测试用例的输入值;
C:赋值装置,用于将装置B中的所述输入值赋给变量,所述变量的数据类型包括基本类型和复合类型;
D:底层变量设定装置,用于供用户指定底层函数的底层变量,并将所述底层变量加入装置B,所述底层函数,是指被测试函数调用的函数,所述底层变量包括以下变量之一或以下变量的任意组合:
所述底层函数的返回值、所述底层函数的输出参数、所述底层函数改写的成员变量、所述底层函数改写的全局变量,
所述底层变量的数据类型包括基本类型和复合类型;
E:底层输入设置装置,用于查询用户在装置B中是否设置了所述底层变量,及调用装置C和/或让所述底层函数继续执行;
F:函数调用拦截装置,用于拦截所述底层函数的调用,并调用装置E。
2.根据权利要求1所述的单元测试系统,其特征在于,所述类型信息包括:类型名称、内存大小,各成员的成员名称、类型名称、偏移量。
3.根据权利要求1所述的单元测试系统,其特征在于,所述赋值装置包括:递归扫描变量及其成员,对需要初始化的变量或成员初始化,对于对应输入值不为空的变量或成员,拷贝对应输入值;所述对应输入值,是指所述树表装置中,变量或成员对应的当前用例的输入值。
4.根据权利要求1所述的单元测试系统,其特征在于,装置D所述的底层变量进一步包括:用于控制所述底层函数是否直接跳过的变量。
5.根据权利要求1所述的单元测试系统,其特征在于,装置D所述的底层变量进一步包括:所述底层函数的被调用次数,装置B所述的表格进一步包括:供用户填写测试用例的输出值的单元格。
6.根据权利要求1所述的单元测试系统,其特征在于,装置D进一步包括:解析被测试代码获得可能的底层变量列表供用户选择。
7.根据权利要求1至6任一权利要求所述的单元测试系统,其特征在于,装置F包括以下步骤之一或以下步骤的任意组合:
函数钩子,用于在所述底层函数被调用时跳转到装置E;
指令跳转,用于在所述底层函数被调用前跳转到装置E;
插入拦截代码,用于在所述底层函数插入拦截代码,所述拦截代码在所述底层函数实现代码执行前执行,并调用装置E;
代码替换,用于将对所述底层函数的调用替换为对代替函数的调用,所述代替函数,是指具有调用装置E功能的代替所述底层函数的函数。
8.根据权利要求7所述的单元测试系统,其特征在于,所述代码替换包括:如果所述底层函数未实现或被隔离,则用与所述底层函数同名的函数代替所述底层函数;否则用与所述底层函数不同名的函数作为所述代替函数,并直接修改被测试代码或通过预编译机制间接修改被测试代码,将对所述底层函数的调用替换为对所述代替函数的调用。
9.根据权利要求1所述的单元测试系统,其特征在于,用特征G代替特征B:
G:表格装置,用于供用户填写测试用例的输入值。
10.一种支持表格驱动底层输入的单元测试方法,包括测试驱动代码,其特征在于,包括:
A:类型解析步骤,用于解析数据类型定义获得类型信息;
B:树表步骤,所述树表由树形控件和表格控件组成,用于树状显示变量及其成员,并提供表格供用户填写测试用例的输入值;
C:赋值步骤,用于将所述树表中的所述输入值赋给变量,所述变量的数据类型包括基本类型和复合类型;
D:底层变量设定步骤,用于供用户指定底层函数的底层变量,并将所述底层变量加入所述树表,所述底层函数,是指被测试函数调用的函数,所述底层变量包括以下变量之一或以下变量的任意组合:
所述底层函数的返回值、所述底层函数的输出参数、所述底层函数改写的成员变量、所述底层函数改写的全局变量,
所述底层变量的数据类型包括基本类型和复合类型;
E:底层输入设置步骤,用于查询用户在所述树表中是否设置了所述底层变量,及调用步骤C和/或让所述底层函数继续执行;
F:函数调用拦截步骤,用于拦截所述底层函数的调用。
CN201310703548.8A 2013-12-19 2013-12-19 一种支持表格驱动底层输入的单元测试系统和方法 Active CN104731695B (zh)

Priority Applications (1)

Application Number Priority Date Filing Date Title
CN201310703548.8A CN104731695B (zh) 2013-12-19 2013-12-19 一种支持表格驱动底层输入的单元测试系统和方法

Applications Claiming Priority (1)

Application Number Priority Date Filing Date Title
CN201310703548.8A CN104731695B (zh) 2013-12-19 2013-12-19 一种支持表格驱动底层输入的单元测试系统和方法

Publications (2)

Publication Number Publication Date
CN104731695A CN104731695A (zh) 2015-06-24
CN104731695B true CN104731695B (zh) 2018-11-09

Family

ID=53455605

Family Applications (1)

Application Number Title Priority Date Filing Date
CN201310703548.8A Active CN104731695B (zh) 2013-12-19 2013-12-19 一种支持表格驱动底层输入的单元测试系统和方法

Country Status (1)

Country Link
CN (1) CN104731695B (zh)

Families Citing this family (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN106055481B (zh) * 2016-06-02 2020-03-27 腾讯科技(深圳)有限公司 计算机程序的测试方法及装置
CN111159033B (zh) * 2019-12-25 2023-07-04 口碑(上海)信息技术有限公司 一种软件测试方法及装置
CN112181851B (zh) * 2020-10-27 2023-07-28 北京字跳网络技术有限公司 软件测试方法、设备及存储介质

Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN1908892A (zh) * 2005-08-01 2007-02-07 王彤 测试用例设计方法和系统
CN1949186A (zh) * 2006-11-17 2007-04-18 深圳市领测科技有限公司 一种程序调测系统及用于程序调测系统的映射方法
CN101110055A (zh) * 2007-08-31 2008-01-23 中兴通讯股份有限公司 在单元测试中实现通用桩函数的装置及其实现方法
CN101110024A (zh) * 2007-08-14 2008-01-23 中兴通讯股份有限公司 一种单元测试系统和方法

Family Cites Families (2)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20080115114A1 (en) * 2006-11-10 2008-05-15 Sashank Palaparthi Automated software unit testing
US8954929B2 (en) * 2010-03-29 2015-02-10 Microsoft Corporation Automatically redirecting method calls for unit testing

Patent Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
CN1908892A (zh) * 2005-08-01 2007-02-07 王彤 测试用例设计方法和系统
CN1949186A (zh) * 2006-11-17 2007-04-18 深圳市领测科技有限公司 一种程序调测系统及用于程序调测系统的映射方法
CN101110024A (zh) * 2007-08-14 2008-01-23 中兴通讯股份有限公司 一种单元测试系统和方法
CN101110055A (zh) * 2007-08-31 2008-01-23 中兴通讯股份有限公司 在单元测试中实现通用桩函数的装置及其实现方法

Non-Patent Citations (2)

* Cited by examiner, † Cited by third party
Title
"ATC系统软件自动化单元测试工具的研究与实现";张秀琼;《万方数据》;20070807;第三至五章 *
"c/c++单元测试底层模拟技术";刘跃勇 等;《计算机系统应用》;20121130;第21卷(第11期);第156-160页 *

Also Published As

Publication number Publication date
CN104731695A (zh) 2015-06-24

Similar Documents

Publication Publication Date Title
KR102323378B1 (ko) 데이터 처리방법 및 관련제품
CN102915242B (zh) 一种利用图形化操作实现代码编程的方法
CN101589366B (zh) 面向生成器图的编程框架中的并行化和植入
CN101601012B (zh) 具有场景支持的面向生成器图的编程框架
Fischer et al. Story diagrams: A new graph rewrite language based on the unified modeling language and java
CN107066256B (zh) 一种基于时态的对象变更模型的建模方法
CN113835695B (zh) 基于统一后端引擎的深度学习框架与硬件设备适配方法
CN107368408A (zh) 一种面向接口的软件故障注入自动化测试方法
CN103327080B (zh) 创建物联网控制系统的方法及装置
CN104731695B (zh) 一种支持表格驱动底层输入的单元测试系统和方法
CN110287088B (zh) 一种基于动态ui模型的自动化测试方法
CN101408849A (zh) Ttcn-3语言的编译执行方法及系统
CN112199086A (zh) 自动编程控制系统、方法、装置、电子设备及存储介质
Xu et al. Using adaptive agents to automatically generate test scenarios from the UML activity diagrams
CN110673844A (zh) 一种图像处理软件开发方法及系统
CN107153749A (zh) 一种卫星矩阵电缆接点设计工具及设计方法
Eitan et al. Adaptive behavioral programming
CN109976723A (zh) 一种算法开发平台、算法开发方法及计算机可读存储介质
Isaac The ABM template models: A reformulation with reference implementations
CN106096159B (zh) 一种云平台下的分布式系统行为仿真分析系统的实现方法
CN115185539A (zh) 一种生成可执行动态链接库文件方法、装置及存储介质
Kirshin et al. A UML simulator based on a generic model execution engine
CN104731700B (zh) 一种支持表格驱动局部数据的单元测试系统和方法
CN110362334A (zh) 二次开发语言的c++对象生命周期管理方法、设备、介质
CN106354633A (zh) 基于算法插件的任务调度表生成方法

Legal Events

Date Code Title Description
C06 Publication
PB01 Publication
SE01 Entry into force of request for substantive examination
SE01 Entry into force of request for substantive examination
CB02 Change of applicant information

Address after: 510315 UP Chi Chi C2-209, 29, West Road, Hongwei new village, Haizhuqu District, Guangzhou, Guangdong.

Applicant after: Guangzhou Kaile Software Technology Co., Ltd.

Address before: 510630 303, room 244, five mountain road, Tianhe District, Guangzhou, Guangdong.

Applicant before: Guangzhou Kaile Software Technology Co., Ltd.

CB02 Change of applicant information
GR01 Patent grant
GR01 Patent grant