1.4 软件测试发展展望
1.4.1 软件测试面临的挑战
1.4.1.1 面向故障的软件测试
1.故障模型
缺陷检出、分析、处置是软件测试发展的内生动力,故障模型是基于缺陷的软件测试的理论基础。对于任意软件Software,假设是可能的任意故障集合,是一个确定的测试方法,CM是基于对给定和F所生成的测试用例集,是CM所能检出的故障集合,是产生CM所花费的代价,譬如生成并执行CM所需的时间,我们期望通过最少的测试用例,以最小的代价达成测试目标,即获得最小化的CM和。对于两个不同测试方法和M2,若,且,则认为M1优于。显然,这种方法未必会存在。通常,只要在可控范围之内且不会无限扩大,且,则可以断定优于。然而,由于对软件失效机理认知的局限性、软件缺陷描述的不确定性、软件缺陷定位的不精准性,目前还难以建立统一或普适软件故障模型,这是面向故障软件测试及软件测试理论发展的主要瓶颈之一。
2.单故障模型
假设软件故障为“小故障”或可以分解为小故障。与所谓“正确”的软件相比,软件逻辑结构正确,其错误表现为变量替代错误、运算符遗漏、括号偏移等一个或几个符号错误。面向单故障模型测试是基于单故障模型假设,对于任意给定程序,生成故障集合F={f1,f2,⋯,fn} ,基于面向故障的测试用例,生成故障模拟算法及能够检测中所有故障的测试用例,以检测软件中存在的小检测概率故障,但精准的元素定位问题无法保证模型拟合度的无偏性。
3.系统崩溃测试
对于一个软件系统,即使某个或某些缺陷被激活,亦未必会诱发系统失效,但在不可预知的条件下,如果缺陷被多次激发,则可能导致系统崩溃。例如,对于以C++实现的程序,虽然已有大量测试工具能够检出其内存泄漏、数组越界、空指针引用等静态缺陷,但C++语言因其缺乏与内存安全相关的特性,存在缓冲区溢出、悬空指针等问题,特定触发或场景下,可能导致程序崩溃、未定义的行为,甚至是安全漏洞。但C++语言广泛使用带来的高扩散性,使得针对这种情况的测试场景构建、触发条件设置、数据阈值预置等可能处于不可控状态。
4.域比较测试
假定软件需求规格通过完备测试,而且能够从需求规格和代码DP两个方面得到软件的定义域,那么,“软件正确”的必要条件就是,也就是软件设计与实现同需求规格完全契合,软件设计、编码实现完整、准确地实现了软件需求。反之,若,则表明软件设计及实现同需求规格不一致。对于x∈(DS−DP)∪(DP−DS) 中的点,一般是软件中一个特别的点,但往往可能会被开发人员所忽略或遗漏。例如,对一元二次方程求根的程序,设计及实现过程中,可能会忽略的情况。当然,除数为0的点,负数开平方的点,其他不该取值的点等,莫不如此。对于这类情况,可进行域比较测试,全面、系统地检验软件不同输入空间所对应输出的正确性。但是,对于域比较测试,子域分割图构建、边界测试点选择、子域内测试点选择、测试结果比对等的理论解释、实践方法,尚待进一步深入研究。
1.4.1.2 基于规范的软件测试
基于规范的软件测试具有坚实的理论基础,构建了较完备的技术标准体系,拥有丰富的测试工具支撑,且已通过广泛的实践验证。逻辑覆盖、路径覆盖、符号执行、边界测试、组合测试、数据驱动测试、软件成分分析等都是重要的基于规范的软件测试技术。其中,被动测试、符号执行、组合测试、数据驱动测试、软件成分分析还面临着挑战,在此予以简述。
1.被动测试
主动测试是由测试人员向被测应用发送测试输入,将测试输出同预期结果比较,判定测试结果。对于主动测试,软件系统处于被测状态而非正常工作状态,环境确定,场景预置,难以实现充分的系统动态行为测试、基于场景驱动的系统能力测试,尤其是对于多协议变量复杂系统,无法实现在线测试,难以实现真实运行状态下的性能测试,环境差异会对测试结果产生重要影响。
被动测试则是在真实环境下运行被测软件,在正常工作状态下及应用场景中,被动接收输入,在不干预软件运行的情况下,根据I/O序列,判定软件状态,预测下一个输出。一般地,被动测试过可分为自动导引(Homing)和故障检测两个阶段。有限状态机(Finite State Machine,FSM)是被动测试的重要方法,包括遍历所有状态转移测试序列的T方法、构造测试输入序列的D方法及状态验证的U方法,模型简单且易于实现,但它仅考虑了系统的控制流而未考虑数据流,对于系统流程测试,力难从心。基于FSM、扩充输入输出参数、上下文变量、定义在上下文变量、输入参数上的谓词条件和操作,构造扩展有限状态机(Extended Finite State Machine,EFSM),既可以表达控制流,也能够表达数据流,能够更加准确地描述复杂系统。但是,由于软件系统可能处于随机状态,如何处理其变量,是EFSM面临的难题之一。不确定的变量处理、变量区间表示及其处理是该技术领域研究的重点。
2.符号执行
符号执行是使用变量名称的符号值而非真实数据作为程序输入,采用前向扩展和后向回溯执行程序,对源程序进行词法、语法分析,生成关于输入符号的代数表达式,用于程序路径检查、程序证明、程序简约及符号调试,检出程序缺陷,较好地解决了定理证明、类型推导、抽象解释、模型检测、规则检查等存在的问题,可为缺陷触发提供具体输入,是静态分析的重要手段。如果代码中存在数组元素、复杂数据结构、循环及方法调用等情况,自动定理证明需借助于各种判定程序,判断被测算法是否为定理,不能直接用于程序分析;类型推导仅适用于函数式程序设计语言;抽象解释只能作用于确定的抽象域;基于模型检测的搜索算法效率较低,且可能导致状态空间爆炸;规则检查受制于规则描述机制,只能对特定类型缺陷进行分析。
3.组合测试
组合测试是基于多参数故障模型,基于系统参数的相互作用及取值组合,以较少的测试用例,实现测试目标,是基于测试性能及代价约束的优化问题。假设k个参数相互独立,其中第个参数有个取值。表示第个参数的某个取值即水平,表示一个测试用例,表示所有可能的测试用例构成的集合,表示选定的某个测试用例集,,对这些参数的全部组合进行测试,需个测试用例。当参数个数或其取值个数ni很大时,测试用例数将会是一个庞大的数字,难以或无法实现全组合测试,需要从全部组合中选择最少的测试用例,以达到确定的测试目标。
理论上,可以通过有限输入空间表示无限输入空间,但只能解决单个输入的取值问题,必须为每个输入确定相应的取值,驱动系统运行。如何通过不同输入组合,解决测试组合爆炸问题,保证测试的充分性,是软件测试所需面对的基本问题。
4.数据驱动测试
数据驱动测试(Data-Driven Testing,DDT)是一种从Excel表格、JSON文件、数据库等外部数据源读取测试数据,以参数形式输入测试脚本,驱动测试的软件测试技术。数据驱动测试将测试用例中的执行逻辑与数据分离,较好地解决了数据存储、读取、测试执行及测试结果写入等问题,测试脚本简练,可以灵活地添加测试数据,具有良好的可理解性、可重用性、可扩展性、可维护性,能够显著地提高测试覆盖率和测试效率,广泛地应用于接口测试、性能测试、网站测试等场景,是自动测试的重要组成部分。但是,数据驱动测试用例生成和执行强依赖于数据,对测试数据设计提出了非常高的要求。同时,冗余测试用例的优化处理,也是不得不面对的问题。
5.软件成分分析
软件成分分析(Software Compostition Analysis,SCA)是通过软件源码分析,提取项目依赖的第三方组件及其版本、许可证、模块、框架、库等特征信息,识别跟踪项目中引入的开源组件,检测相关组件、支持库及它们之间的依赖关系,识别已知的安全漏洞及许可证授权问题,提高软件系统抗恶意软件包渗透、攻击软件和应用程序威胁的能力,规避开源软件所带来的合规性、知识产权等风险。
基于构建文件的软件成分分析是通过提取开源组件特征信息,识别开源组件及第三方依赖项风险,但SCA并不查找自定义代码中的安全漏洞,不检测不安全的网络配置,无法缓解SolarWinds供应链等漏洞,对于安装痕迹模糊或用户选择性安装的组件,存在分析结果准确性偏差;基于代码相似度的软件成分分析依赖于分析算法及已知漏洞数据库和组件数据库,虽然能够在大规模组件库支持下进行快速计算,检测潜在的安全风险,但受限于数据源及其更新及时性等问题,可能无法发现最新的安全漏洞或某些特定的组件;基于静态软件成分分析,无法对已投入生产或动态加载的组件进行识别和分析,可能导致一些重要的安全风险被忽略。
1.4.1.3 基于架构的软件测试
1.移动互联测试
移动应用种类繁多的移动设备、复杂多变的应用环境、千差万别的应用场景、持续引入的新特性,对移动互联测试提出了新的要求。基于逻辑、数据、剖面的测试为移动互联测试提供了基础支撑,解决了基本的测试需求;基于软件即服务(Software as a Service,SaaS)系统的多租户架构,负载均衡、容错处理、备份恢复等技术手段,身份认证、访问控制、漏洞管理等安全策略,构建移动互联测试平台,集成Monkeytalk、Appium等自动化测试工具,模拟用户真实的终端操作方式,将应用提交到平台中,实现全量功能性能测试、全链路压测、流量回放、跨地域跨时区测试、安全性测试,支持应用在不同平台上的多版本适配,较好地支撑了移动互联测试的工程实践。但即便如此,移动互联测试还面临着设备和操作系统的多样性、平台及操作系统不断更新、网络环境下的系统性能和稳定性、用户体验及手势操作测试、系统安全性及隐私保护等挑战。
2.云服务测试
将测试服务部署到云上,即可根据需求使用云端资源,将云平台和容器技术结合,能够快速构建可扩展、可伸缩的测试环境,基于使用场景驱动测试,对基于弹性伸缩模型的云计算服务设施的弹性能力及基于故障注入的云计算服务设施进行测试,减少用户的基础设施投入,降低成本。
云服务包含私有云、公有云、混合云等不同形态,规模庞大、架构复杂、配置困难、计算及存储量巨大,其高负载、高扩展、动态部署等特点,对云服务测试提出了新的更高要求。首先,软件测试人员必须深入分析云架构的结构及技术特征,开发基于云架构的测试技术及测试策略,构建符合云平台质量要求的测试工程能力和质量保障能力;其次,对于云计算平台功能性能、可扩展性及弹性测试,传统软件测试工具力难从心,通过负载测试、压力测试、基准测试及系统的可伸缩性验证,能在一定程度上避免超大规模云端压力模拟所带来的困难,但需要网络运营商、CDN服务提供商支持,代价高昂;再次,云计算环境中,错误类型众多、错误信息表达形式各异、相同的错误在不同云产品上表达不一致、业务错误码与HTTP错误码含义不匹配、错误码超越可枚举集合,如此等等,无一不是云服务平台容错性和可靠性测试难以逾越的障碍;最后,云计算环境中,配置参数及其组合数量巨大,虽然我们可以采用组合测试技术缩减组合数,但如何完成巨量的组合测试,保证其覆盖率,存在较大质量风险。
3.区块链测试
区块链是一种去中心化、跨越多个子网、多个数据中心、多个运营商甚至多个国家的分布式系统,通过一系列基于时间顺序排列的数据块即所谓“区块”记录数据,通过加密技术确保数据的不可篡改、不可伪造性,规模庞大、边界模糊、交易复杂、安全性要求高。区块链测试不仅涉及前端API与某个区块链节点之间的测试,还涉及大量区块链节点之间的测试,不仅需要测试验证其功能、性能、安全性、兼容性、容错性、数据一致性等特性,还需要对共识算法的合法性、完整性、可终止性及智能合约等进行测试验证。首先,区块链涉及网络、存储设备等基础设施安全性、网络协议安全性、加密算法安全性、共识算法漏洞等共识机制安全性,智能合约安全性,Web、移动客户端软件、数字钱包等应用安全性及身份认证与鉴别等极高的安全性要求,其安全性测试极具挑战性。其次,区块链网络采用工作量证明(Proof of Work,PoW)、权益证明(Proof of Stake,PoS)等共识机制,这些共识机制算法复杂,对测试提出了极高的要求。再次,智能合约类似于法律,在执行过程中,一切均听命于事先设定好的代码,而事先设定好的代码一旦上线就不能轻易修改,如何通过测试,确保智能合约百分之百正确,本来就是软件测试领域的一个悖论。最后,公有链、私有链、联盟链等不同类型的区块链,其网络节点、共识机制、智能合约、身份认证、运行管理等方面存在着较大差异,如何进行一致性测试验证和分析评价,是区块链测试面临的又一难题。
4.物联网测试
物联网(Internet of Things,IoT)是一个集大量网络设备、感知设备及计算、存储等基础设施于一体,人−机−物互联融合的复杂巨系统(Complex Giant System,CGS)。其广泛使用诸如MQTT、OPCUA、ModBus-TCP等工业协议,规模庞大,结构复杂,系统元素及其之间的关系具有不确定性,使用场景复杂多变,解决方案多元化,无一不对IoT测试带来挑战。首先,测试环境复杂,如异构互联、M2M互联、软硬件紧密耦合,需构建全新、规模庞大的测试环境,基于IoT场景仿真,尽管可以在少量物理设备上创建不同类型的虚拟设备,构建不同协议的虚拟连接,模拟应用场景,但难以甚至无法针对所有loT设备、连接协议、服务节点,实现全域、全业务链路的测试覆盖。其次,对于IoT系统测试,必须基于系统所有设备时间同步,虽然基于实践敏感网络(Time Sensitive Network,TSN),建立通用时间框架,支持实时数据采集、实时数据同步传输,但如何在网络震荡的情况下保持高度的时间同步?如何实现基于多系统、多设备、对协议协调的整网配置?在赋能客户同步迭代升级的同时,如何平滑地切换至TSN?如何优化流量传输的确定性?都是目前尚待进一步研究解决的问题。最后,网络安全策略、配置组合、通信协议兼容、系统可伸缩性、系统可扩展性、协同感知、大数据处理性能、智能特性测试及可靠性评估,是一个测试技术创新与应用,测试有效性与效率平衡的系统工程,也是IoT测试面临的重大挑战。
1.4.1.4 大数据及应用测试
传统软件测试技术和方法难以在确定的条件下、给定的时间内获得大数据及应用系统期望的目标结果,甚至无法找到问题的入口到底在哪里。大数据及应用测试包括对数据本身及大数据应用测试两个维度。大数据测试是对数据的完整性、准确性、一致性、及时性、可用性等进行的测试验证,旨在剔除缺省、重复、错误数据,获得理想的数据集,保证数据质量。对于海量、多源非结构化大数据测试,需要搭建可扩展、具有良好伸缩性的测试平台,模拟大量测试客户端,对测试数据的完整性及数据备份、数据管理提出了前所未有的新要求。同时,面对大数据多场景下输出的不确定性、大数据结构的多样、动态性等,定位数据的关联关系面临着巨大挑战。
基于分布式集群环境及数据相关性分析、数据分类、数据聚类、个性化推荐、趋势预测等典型应用场景,大数据应用系统输出的正确性、有效性不仅与大数据质量、架构及算法等密切相关,还有赖于输入数据及其分布特性,具有未知性和不确定性。针对大数据特征及其应用需求,基于大数据架构及层次分解,对大数据算法、数据架构、大数据应用性能、成功处理海量数据的能力及安全性等进行测试验证,是大数据应用测试的重要内容。
1.4.1.5 软件测试分析
软件测试性分析与设计是减少测试复杂性、提高测试效率的重要手段之一,是软件测试复杂性度量的重要方法学。20世纪90年代以来,业界提出简明性、复杂性度量等测试分析设计方法,测试覆盖及缺陷传播、感染、执行(Propagation-Infection-Execution,PIE)等定量分析技术得以深入研究,取得显著成效。
1.测试覆盖
测试覆盖是指测试系统覆盖被测系统的程度,即一项或一组给定测试,对于确定系统或构件的所有指定测试用例进行处理所达到的程度,是测试终止及测试充分性的重要度量,也是测试质量评价的重要依据。一般地,测试覆盖包括需求、逻辑、功能、能力等覆盖目标、测试度量及分析方法。
设是程序P的任意缺陷集合,E是程序中某个元素,如语句、分支、路径、谓词、分支-谓词、C-应用、P-应用、ALL-应用等,是程序P中所有符合元素定义的集合,T是测试用例集,是T对PE的覆盖率。逻辑覆盖包括语句、判定、条件、判定−条件及修正条件判定等覆盖类型,分支−谓词、ALL-应用具有良好的测试覆盖性。逻辑覆盖研究的问题是:当为一个确定值如RPEC=1 时,执行测试用例集,能够检测到的缺陷集合为FT,逻辑覆盖分析就是和FT的相关性分析。测试覆盖解决的主要问题就是如何使及当RPEC=1 时,获得的取值。
2.PIE技术
在特定环境及条件下,缺陷代码能感染其他代码,生成错误的程序状态,当被感染代码执行时,将导致软件功能异常、性能下降,甚至失效。跨站脚本(Cross-Site Scripting,XSS)攻击是一种基于代码注入的网站应用程序的安全漏洞攻击手段。例如,针对Popup Builder插件的XXS漏洞(CVE-2023-6000),攻击者通过构造恶意输入,将恶意脚本注入网站的自定义JavaScript中,恶意脚本在浏览器中执行,当用户访问受感染的网页时,就会被重定向到恶意目的地,用以窃取用户信息、安装恶意软件或进行其他形式的网络攻击。感染亦可能向下传播和蔓延。
执行给定的测试用例,观察软件的执行状态及输出,将每个缺陷的检测划分为故障的元素以执行概率Ef被执行,执行时以变异概率If发生变异,的变异以传播概率Pf传播到输出3个部分,得到故障f的检测概率为Df=EfIfPf,由此对软件中可能存在的故障进行估计,分析失效产生的上下文,识别可疑代码及“缺陷-感染-失效”链,查找失效根源,消除缺陷。
3.信息屏蔽分析
程序中,当一条语句向另一条语句过渡时,有些缺陷可能被一些特别的语句屏蔽。这种情况常见于多对一函数中如关系表达式、BOOLEAN表达式、特殊算术表达式如mod()函数等。一般地,我们难以通过测试检出这些表达式中所包含的错误。尽管通过增加测试点,能够屏蔽缺陷,但测试点增加具有随机性,基于随机模型的测试将带来不可预知的不确定性因素,进而大幅增加工作量。
4.综合评价
基于目标−问题−度量元(Goal-Question-Metric,GQM)建立综合评价模型,是一种有效的评价策略。GQM是一个继承性结构,自上而下,逐层分解,逐步求精,最终基于特定目标得到所需度量。基于确定的度量,将测试类型作为评价的目标和判断依据,通过一个可操作的定义考察每个测试类型中测试用例的执行情况,建立GQM结构,构造评价指标体系并将其逐级分解为所需解决的问题,细化到具体问题需要用到的度量元,对指标进行评价。
模糊评价将评价目标看成由多种因素组成的模糊集即因素集μ,设定因素所能选取的评价等级,组成模糊集,分别求出各单一因素对各评价等级的归属程度,构造模糊矩阵R,然后确定各主因素下的单因素权重A和主因素权重,根据各个因素在评价目标中的权重分配,计算模糊矩阵合期(A, R),给出评价的定量值。