刘 辉,杨永凯,刘中一
(1.民航旅客服务智能化应用技术重点实验室,北京 101318;2.中国民航信息网络股份有限公司,北京 101318)
近年来,随着业务复杂度的不断提升,高效、可靠地保障企业级软件质量,杜绝各种运营事故和安全风险,是所有企业面临的严峻挑战。众所周知,软件质量会影响项目的进度、成本和范围,最终影响客户对企业的信赖。因此,企业对软件质量的要求日益增高。为了保证软件质量,在开发过程中引入了多种软件测试技术[1-2]。目前国内公司主要是以功能测试为主,功能测试的技术手段又以手工测试为主,而自动化测试是在手工测试之后进行的,主要用于回归测试阶段。自动化测试是软件测试活动中一个重要的分支和组成部分,即利用工具或脚本达到测试目的,没有人工或者极少人工参与的软件测试活动称为自动化测试。自动化测试可以方便地进行回归测试,尤其是在敏捷开发过程中,版本快速迭代,自动化测试更具优势[3-4];自动化测试可以提升效率,减少重复工作,节省人力成本,让测试人员可以做更多有意义事情,比如探索性测试[5]等;自动化测试可以保证每次测试的完整性和一致性,发现更多隐藏问题。
软件系统中的多种功能维度[6]会在生产业务的推动下,演变出各种功能点的组合。自动化测试需要完备的功能测试用例库[7-8],业界已经有大量人员研究测试用例生成方法[9-11]。
本文第2部分首先分析了手工构造测试用例的基本方法;然后提出了精简与自动生成测试用例方法,主要思想是根据业务场景分类业务数据,构造功能点组合矩阵,归并、精简业务场景之间的功能点组合矩阵,再执行生产请求,匹配功能点组合矩阵,自动生成测试用例;最后举例说明精简与自动生成测试用例方法。第3部分介绍了精简与自动生成测试用例方法的实际应用效果。文章最后对提出的精简与自动生成测试用例方法进行了总结性的讨论。
测试用例包含测试数据、测试请求、期望结果。构造测试用例的基本方法如图1所示。
图1 手工构造测试用例流程
(1)在完成功能需求分析后,测试人员根据功能需求设计测试用例,其中主要是设计测试数据、测试请求以及期望结果。
(2)测试人员根据测试用例的设计文档,手工构造测试数据,依据测试数据构造相应的测试请求和期望结果。
(3)在正式测试前,需要利用现有的软件调试测试用例,如果返回结果与期望结果一致,代表测试用例正确,可以纳入到测试用例库中;如果返回结果与期望结果不一致,需要分析测试用例中的测试数据、测试请求和期望结果,判断哪个部分错误,并修正相应的内容。对修正后的测试用例再次执行,直到测试用例正确为止。
上述测试用例的构造过程全部由人工完成,需要产品、开发、测试互相配合,耗费人力和时间成本巨大,而且覆盖功能点范围有限。随着业务的飞速发展,软件中的多种功能维度会在实际业务的推动下,演变出各种功能的组合,由于开发和测试环节,对业务的敏感度较低,很难快速响应业务变化,识别并构造出符合实际业务的测试用例。
针对上述软件测试过程中手工构造测试用例的问题,本文提出了一种测试用例精简与自动生成方法。将业务数据按照业务场景分类,构造功能点组合矩阵,归并、精简业务场景之间的功能点组合矩阵,减少冗余的测试用例,再执行生产请求,匹配功能点组合矩阵,自动生成测试用例。从而达到聚焦核心功能点、提升软件的代码测试覆盖率,实现提升软件质量和安全、降低人工成本、提升团队交付能力的目的。
2.2.1 功能点组合矩阵构造
在真实的生产环境中,用户通常会预定义一系列的业务场景,业务场景通过功能点组合构建而成,不同的业务场景包含不同的功能点组合。
定义1:功能点组合矩阵。假设某一业务场景包含n个功能点F={f1、f2、...、fn},任一功能点fi的取值集合记为C(fi),功能点组合矩阵是所有功能点取值集合的笛卡尔积,记为A。
功能点组合矩阵的每一行是n元组n-T=(c1,c2,...,cn),其中每个元素即为对应功能点的一种取值。功能点组合矩阵A包含n-T的数量记为|A|。
定义2:标签。一个软件会包括多种业务场景,不同的业务场景相互独立,涉及不同的功能维度,即不同的功能点组合,因此不同的业务场景对应不同的功能点组合矩阵。在每种业务场景下,用户发布一批业务数据,用以描述该业务场景的各种适用条件,并通过一个或多个属性标识出业务数据所属的业务场景,这些属性称为标签D。
本文通过标签D将业务数据划分在不同的业务场景下,根据业务场景涉及到的功能点F,提取出业务场景的元组T,分析业务场景下各功能点的取值集合C,构造功能点组合矩阵A。
2.2.2 测试用例精简
定义3:测试子集,测试超集。假设存在2个业务场景的功能点组合矩阵A1和A2,其功能点分别为F1和F2,若
则,A1是A2的测试子集,A2是A1的测试超集,记为A2→A1。
定理1:2个业务场景的功能点组合矩阵A1和A2,若A1是A2的测试子集,则|A1| ≤|A2|。
证明:2个业务场景的功能点组合矩阵A1和A2,其功能点分别为F1和F2,A2→A1。
根据定义3,F1⊆F2,|F1|≤|F2|,假设n1=|F1|,n2=|F2|,n1≤n2;
又根据定义3,∀f∈F1∩F2,C1(f)⊆C2(f),|C1(f)|≤|C2(f)|;
证毕。
定理2:测试超集测试通过,其测试子集必然测试通过。
证明:2个业务场景的功能点组合矩阵A1和A2,其功能点分别为F1和F2,A2→A1。
测试超集测试通过,则∀f∈F2,功能点f测试通过。
假设测试子集测试不通过,则∃f∈F1,功能点f测试不通过。根据定义3,f∈F2,功能点f测试不通过,与前提条件不一致。因此,假设不成立,测试子集测试必然通过。
证毕。
本文所提测试用例精简方法,主要采用降维和归并2种策略,具体描述如下:
(1)降维。假设全业务功能点组合矩阵H包含m个功能点E,将业务数据按照业务场景划分后,某业务场景的功能点组合矩阵A包含n个功能点F。根据定义3,业务场景的功能点组合矩阵是全业务功能点组合矩阵的测试子集,H→A,F⊆E,n≤m,根据定理1,|A|≤|H|。
在软件中,通常采用关系型数据库保存业务数据,所有业务场景的业务数据融合在相同的表空间中,共享相同的数据表,因此数据表拥有所有业务场景涉及到的功能点字段。尽管在技术上按照业务类别将功能点字段划分在不同的表中,可是相对于某一确定的业务场景,仍然会有多余的功能点字段。通过划分业务场景,可以避免全功能点组合,在不失测试完备性的前提下,有效地对业务数据降维[12],减少每种业务场景的功能点组合矩阵元组数量,从而精简测试用例[13-15]。
(2)归并。假设存在2个业务场景的功能点组合矩阵A1和A2,其功能点分别为F1和F2,A1是A2的测试子集A2→A1。根据定义3,F1⊆F2,根据定理2,A2测试通过,A1必然测试通过。
软件中不同的业务场景之间存在着相似性,甚至内容相同,只是定义的标签不同。如果某个业务场景涉及到的功能点字段包含另一个业务场景涉及到的功能点字段,并且相同功能点字段在该业务场景中的取值集合包含在另一个业务场景中的取值集合,只需要测试该业务场景即可。因为该业务场景涉及到的功能点字段更全,取值范围更广,囊括了另一个业务场景的各种情况。通过归并业务场景,可以剔除冗余的业务场景,避免重复测试,减少冗余的测试用例,达到精简测试用例的目的。
2.2.3 测试用例自动生成
本测试用例自动生成方法是侵入式的,需要在现有软件中打桩,记录软件的执行路径,将相关信息以结构化的形式进行存储。此外本方法还依赖于海量的业务数据和生产日志,需要在其中筛选出符合业务场景测试需求的用例。下面将介绍该方法的实现步骤。
输入:业务数据
生产日志
输出:测试用例集
(1)初始化测试用例集为空集。
(2)构造精简的功能点组合矩阵,定义测试需求。
(3)基于打桩程序框架,在软件的功能点实现打桩功能。
(4)执行生产日志中的请求,筛选并构造测试用例。
(5)遍历生产日志。基于打桩后的软件程序和业务数据,执行每一条生产日志请求;打桩程序记录各个功能点的执行信息,包括功能点的名称、请求参数、业务数据内容,以及处理结果等信息;提取并分析各个功能点的执行信息,识别执行到的功能点;匹配测试需求,如果该生产日志请求的执行路径首次覆盖到的功能点组合矩阵的某一元组,将此生产日志请求存入测试用例库。
(6)直至满足测试需求的完备性,结束遍历。本方法采用真实的业务数据和生产日志作为输入。业务数据是用户根据自身的业务发展情况创建的,最能体现用户的真实业务意图。而生产日志中的请求是用户根据自身的需要发起的,最能体现用户的真实使用意图。因此,生产日志请求和涉及的业务数据,构成了最有价值的测试用例。
匹配测试需求,即匹配功能点组合矩阵。执行每个生产日志请求,将其执行的功能点组合与业务功能点组合矩阵中的每一元组比较,如果生产日志请求执行的功能点组合能够覆盖业务功能点组合矩阵的某一元组,并且之前没有被覆盖过,则将该生产日志请求纳入到测试用例库中,作为测试请求。
打桩程序框架采用外挂模式,对每个功能点增加打桩功能程序,以及打桩开关选项,控制功能点是否执行打桩程序。当需要采集某个功能点的执行信息时,只需要在配置中动态打开该功能点的打桩开关,便可获取到相应的执行信息。打桩程序可以按照软件系统的功能层次记录执行情况,假设在功能A中调用了功能B,则打桩程序的记录结果与之对应,在执行结果A中包含执行结果B的内容。
2.2.4 举例说明
假设某软件有5个功能点,划分为3个业务场景后,各业务场景包含的功能点和取值集合如下:
业务场景一:
功能点1:{a11,a12,a13};功能点2:{b11,b12};功能点3:{c11,c12};功能点4:{d11}。
业务场景二:
功能点1:{a21,a22};功能点4:{d21};功能点5:{e21,e22}。
业务场景三:
功能点1:{a11,a13};功能点3:{c11,c12}。
上述3个业务场景对应的功能点组合矩阵见表1—表3。
表1 业务场景一功能点组合矩阵
表2 业务场景二功能点组合矩阵
表3 业务场景三功能点组合矩阵
由定义3,业务场景三功能点组合矩阵是业务场景一功能点组合矩阵的测试子集,又由定理2,业务场景三功能点组合矩阵可以被精简掉。因此,业务场景一和业务场景二的功能点组合矩阵构成了该软件的测试需求。
遍历生产日志中的请求,针对业务场景一,打开功能点1、功能点2、功能点3、功能点4的打桩开关,记录每个生产日志请求的执行情况。假设某一生产日志请求执行了功能点1、功能点2、功能点3、功能点4,对应的值分别为a11、b11、c11、d11,则覆盖了该业务场景功能点组合矩阵的一个元组4-T=(a11,b11,c11,d11),如果之前没有被覆盖过,该生产日志请求纳入到测试用例库中,为业务场景一的一个测试用例。以此类推,逐步筛选出符合业务场景一的所有功能点组合的生产日志请求,并纳入到测试用例库中。当业务场景一功能点组合矩阵的所有元组被完全覆盖,则业务场景一的测试需求是测试完备的。同理,筛选出业务场景二的测试用例。该测试用例自动生成方法的目标是筛选出能够覆盖功能点组合的生产日志请求,使得所有业务场景的测试需求都是测试完备的。
本实验以民航运价系统为例,使用生产日志和业务数据验证本文所提测试用例精简的效果和自动生成方法的可行性。
民航运价系统,每天处理约2 000万笔交易,生成约120 G日志;包含3年的业务数据,近500 G。本实验使用2022年1月29日交易日期的生产日志和2022年8月25日的业务数据。系统包含3年的业务数据,即2019年8月26日—2022年8月25日三年的全部数据内容。
以国航运价业务数据为样本,共涉及323 897条样本数据,10个功能点,功能点分别为:去程星期限制、回程星期限制、提前购票限制、运价组合限制、团队人数限制、团队拆分限制、缺口程组合限制、往返程组合限制、代码共享限制、适用代码共享承运人。对于该样本数据,不划分业务场景时,需要155 520个测试用例保证测试完备性。
根据标签,可以将样本数据划分为207个业务场景,其中最多涉及7个功能点,最少涉及1个功能点,共需要4 421个测试用例保证测试完备性。经过精简后,可以归并为12个业务场景,其中最多涉及7个功能点,最少涉及2个功能点,共需要2 592个测试用例保证测试完备性。
以精简后的某一业务场景“T/CA3C212619”为例,该业务场景涉及到3个功能点,分别为:
提前购票限制,取值集合为{[0天999天]、[1天999天]};
代码共享限制,取值集合为{[0]、[1]};
适用代码共享承运人,取值集合为{[]、[山航/]}。
该业务场景生成的功能点组合矩阵包含8个3维元组,如表4所示。
表4 业务场景“T/CA3C212619”功能点组合矩阵
某一生产日志请求执行结果如图2所示:
图2 生产日志请求结果
该日志请求的执行结果覆盖了业务场景“T/CA3C212619”功能点组合矩阵的第3个元组,可以纳入到测试用例库中。
本文提出了一种测试用例精简与自动生成方法。首先,测试用例精简方法通过划分业务场景降维,通过归并业务场景减少功能点组合矩阵,解决了测试需求维度爆炸问题,实验结果显示,在保证测试完备性的前提下,有效地减少了测试用例的数量,使得基于路径覆盖的测试具有可行性。再次,测试用例自动生成方法使用生产日志和业务数据,自动分析软件系统的请求以及结果,抓取测试用例,大大提升了测试用例的范围,以及测试覆盖率,并且业务数据和生产请求更加贴合用户的真实业务场景,提升了测试的可靠性,避免了无效的测试。虽然本方法使用的打桩技术是侵入式的,但是可以采用组件挂载技术,通过配置动态开关,控制是否开启打桩程序,对生产系统功能和性能无影响。综上,本文所提方法在工程实践中具有较大的应用价值。