聊聊变异测试

news2024/12/28 3:34:45

软件质量保障

所寫即所思|一个阿里质量人对测试的所感所悟。

1. 介绍

有句话说:证实容易,证伪难。正如测试一样,证明缺陷存在容易,但证明不存在缺陷难。而变异测试颠覆了这一原则,如果我们知道存在缺陷,那么我们的测试结果会如何反映测试的质量呢?

随着工程师越来越多地采用更自动化的软件验证方法,以及在不断缩短的发布周期中对更高品质的软件输出的需求日益增长,变异测试帮助我们退一步评估,我们是否真的应该对我们的测试充满如此信心。

Mutation testing is the process of heuristically determining semantics of your program that are not covered by tests.

变异测试是通过启发式方法确定程序中未被测试覆盖的语义的过程。——Markus Schirp

在多数软件测试方法中,很难预判能否在测试过程中发现缺陷,往往直到这些缺陷在后续的测试环节被发现,甚至是更糟的情况下,在生产环境中出现时才会被注意到。这对于每位测试经理来说都颇为熟悉,因为他们需要根据生产环境发布后获得的经验来反馈并改进测试流程。无疑,是否存在一种更佳的方法来揭示测试覆盖中的问题呢?

变异测试作为一种测试技术,其历史可追溯至1971年,近年来越来越受到重视,现已发展出十几种相关测试工具,并广泛应用于各种软件环境。可用工具的数量自1981年的不足5种显著增长,到2013年已超过40种。

变异测试处在依赖系统期望行为正式规范的测试技术灰色地带,与之并列的还有模糊测试、变形测试以及探索性测试。从根本上讲,变异测试是一种实践,即对软件(所谓的“变异体”)的多个版本执行一组测试。每个待测软件版本都有意且通过编程方式注入了不同的缺陷。每一次测试迭代都是基于启发式方法在软件的一个微小差异版本上进行的——这些规则对应于常见缺陷——注入不同的缺陷。这些版本被称为“变异体”,意指它们是小规模的变异。测试的目的通常是确定哪些缺陷能被测试程序发现,从而导致执行失败。

之所以将软件的这些人造缺陷版本称为“变异体”,是因为它们的变异方式类似于人类基因在自然进化过程中的变异,这与人工智能中使用遗传算法解决搜索和优化问题有相似之处。

变异测试的好处可能非常明显,它能为以下方面提供极为有用的洞察:

• 自动化测试的质量和覆盖范围,尤其是断言和验证的覆盖充分度情况

• 特定测试设计技术的成功实施

• 代码不同模块的复杂度和可维护性

• 通过测试追溯组件到整体业务功能的能力

它可以作为一种方法来改进现有测试集,以确保有足够的测试验证或优先针对代码的特定模块进行测试。最终,它提供了一组关于质量的真实信息,这些信息通过其他方式是无法获得的。

2. 自动化测试

从概念上讲,变异测试并不局限于自动化测试;从原则上讲,它是一种可以应用于手工测试的方法。然而,在大多数情况下与运行数千次手工测试相关的成本无法与收益相提并论。

自动化测试的核心挑战之一是确保断言和验证点的同步。测试工程师理应感知更多的上下文知识,并利用专家经验来确定测试用例的预期并进行断言。与手工测试不同,自动化测试集的本质是,它们只会验证预期存在的缺陷——换句话说,它只会对预期内的返回做断言。举个最极端的例子,你可以创建一个自动化测试,启动要测试的软件,只需验证它可以成功运行,而不对程序输出内容做任何断言。这将是一个非常易于维护的测试,但也是一个价值非常低的测试,因为它除了告诉我们程序正常运行外,没有告诉我们其他内容。如果使用变异测试来评估这种假设软件和测试,得分将非常低,因为软件的变异版本只有在注入的缺陷导致软件完全运行失败时才会使测试报错。变异测试不能解决测试可维护性的问题,但它确实能对单个测试的实际价值提供一定的见解。这一点也很重要,因为即使在一个自动化程度很高的环境中,人们也往往不会执行全面的组合测试,因为它被认为是一种不切实际的资源使用方式。任何测试设计技术都存在一个风险,即测试用例爆炸,也就是说,当你专注于一种特定的测试设计技术时,测试的数量会急剧增加。

3. 代码覆盖率和变异运算符

变异测试是一种黑盒测试技术,测试人员做测试设计和执行不需要了解代码的内部执行逻辑,但是变异植入人员必须非常熟悉了解代码。事实上,生成的变异体与底层代码的语言和结构密不可分,真正的缺陷也是如此。当变异植入人员将缺陷注入代码,这里变异体通常可以由编写代码的开发工程师自定义,包括:

•从代码中删除语句

•从代码中插入语句

•更改代码中的条件

•替换变量

让我们回顾一些基本的编程概念以及它们与缺陷、代码覆盖率和变异测试的联系。在大多数编程语言中,可执行语句表示要执行的操作,例如将一个值(例如true或false)分配给一个变量。ISTQB术语表将此定义为:“当编译时,该语句被编译成目标代码,并且在程序运行时将按顺序执行,并且可能对数据执行操作。”例如,在下面的代码中,所有不以IF/ELSE开头的代码都是语句:

allowEntrance = false if(customerHasMembershipCard or customerHasAccessCard):  allowEntrance = true   price = 0 else:   if(weekend):     allowEntrance = true     price = 10

可执行测试集覆盖语句的程度通常被称为语句覆盖率,语句覆盖率是测试集执行的语句的百分比。

语句覆盖率=执行语句数/总语句数

要达到上述代码的完整语句覆盖,你需要两个测试,因为要执行每个语句,需要通过代码中的两个互斥路径。另一种覆盖方法是覆盖每个分支或决策,基本上,只要包含条件语句(如if、for、while),就要确保条件语句的两个结果都被评估。要达到上述示例的完整分支覆盖,你需要一个额外的测试,以覆盖weekend变量是否为真或假。

最后,条件覆盖率是一种代码覆盖率度量标准,它衡量的是每个单个条件是否已被评估为真或假。这可以计算为:

因此,再次以上面的例子为例,确保测试覆盖了会员身份和访问卡场景,为我们不断增多的测试集添加另一个测试。仅使用代码覆盖率指标来衡量自动化测试质量的问题在于,这些指标没有一个可以评估我的测试是否实际上检查了客户是否被允许访问,或者软件计算了多少费用。这些状态和变量的验证不包括在指标中。在自动化测试中测量代码覆盖率固然很好,但这只是画面的一部分。代码覆盖率只告诉你已经执行的逻辑和分支,它不能真正衡量你的测试是否获得了大量的功能覆盖数据,也不能告诉你你的测试是否有效地检测到了缺陷。验证系统响应(有效比较实际结果与预期结果)是实现自动化测试的关键部分,直接检查一个变量是否合理是很容易的;然而,随着接口变得越来越复杂,围绕验证的设计主观性也在增加。变异操作引擎将变异操作符应用于代码,它们支持的操作符各不相同,实际上用户通常可以配置如何应用这些操作符。例如,著名的Mothra研究和支持工具使用了表1中所示的Fortran中的操作符。这些操作符有些过时,因为操作符随着面向对象技术的发展而发展。

当然,潜在操作符的数量及其导致的软件代码变异是巨大的,任何实现都不可能是穷尽的。通过一个变异操作符运行测试软件可能会导致代码中的许多变化。例如,基于规则的操作符应用于此代码:

allowEntrance = false if (customerHasMembershipCard or customerHasAccessCard):   allowEntrance = true   price = 0 else:   if(weekend):     allowEntrance = true     price = 10

在这个例子中,红色项目将被更改。第一个将被初始化为true,第二个将把or改为and,第三个和第四个将通过添加not来否定布尔值。因此,将被编译出四个测试系统的版本,并且变异测试例程应该针对每个版本运行所有自动测试。为了成功检测每个变异体,测试集需要具有以下特征:

•测试如果客户没有两张卡,并且不是weekend,则不允许客户进入。这将测试变异1中未初始化变量的情况。

•测试如果客户有一张卡,但没有另一张卡(完整条件覆盖也需要测试这种情况),然后验证客户被允许进入。

•测试如果客户在weekend没有卡是否被允许进入。

•替换变量​

正如你所看到的,尽管为达到代码覆盖率而构建的测试集会通过代码执行类似的路径,但变异测试指标允许对测试应执行的验证进行更具体的描述。毕竟大多软件缺陷是在编码过程中引入的。例如,常见的“下标偏移”缺陷,即程序员指示循环迭代一次或多次,或者太少——或者误算了边界条件——可以直接通过边界值分析和等价划分等测试设计技术来解决。同样,这种缺陷通常是由变异测试操作员注入的。变异测试过程可以概括如下:

1. 通过插入缺陷来创建变异体。

2. 变异体创建后,选择并执行测试。

3. 如果变异体执行测试时测试失败,则变异体将被“杀死”。

4. 如果变异体测试的结果与基础软件相同,则变异体“存活”。

5. 可以添加新的测试,修改现有的测试或重构代码,以增加“杀死”的变异体数量。一些变异体无法被检测到,因为它们会产生与测试的原始软件等价的输出,这些被称为“等价变异体”。一旦整个过程执行完毕,就可以计算变异体得分。这是杀死的变异体与变异体总数的比率。这个分数越接近1,测试集和软件的质量就越高。

变异得分=杀死的变异体数量/总变异体数量

4. 变异测试的挑战和策略

进行变异测试所需的成本比较高,而且需要大量花费时间来检查和修复发现的问题,需要考虑成本如下:

•生成变异体的编译时间成本

•在变异体上运行测试的运行时间成本

•分析结果的人力成本。

编译时间正如前面提到的,变异测试的一个主要问题是执行成本。变异体的数量是代码行数和数据对象数之积,但通常情况下,生成的变异体的数量通常是代码行数的平方。一些策略已经尝试减少执行量:

  • 抽样——在软件的逻辑区域和相关测试中仅执行变异体的随机样本。

  • 聚类——使用无监督机器学习算法(例如,K-means)来选择变异体。

  • 选择性测试——减少变异体操作符的数量,即用于注入缺陷的启发式方法,可以减少变异体的数量60%。

  • 高阶变异——一阶变异体是那些只注入一个缺陷的变异体;二阶变异体是在多次变异迭代中注入多个缺陷的变异体。高阶变异体更难杀死,而仅关注二阶变异体已被证明可以减少工作量,而不会减少覆盖率。

  • 增量变异——只对变更代码进行变异测试,而不是测试中的整个代码库。

我们知道,缺陷具有集聚性,也许一个简单的策略,将技术应用于有限、复杂、高风险和充满缺陷的功能区域,可以提供成本与收益的适当平衡。相反,代码中有些语句我们不必担心。例如,从变异中排除所有日志语句可能是适当的,并导致更少的变异体进行测试。另一种减少所需时间和资源的方法是直接与编译器集成。早期的变异测试方法单独编译每个变异体;然而,更现代的方法编译一次,然后对中间形式(如字节码)进行变异。这在编译性能方面具有显着优势,但在评估每个变异体的执行时间方面没有优势。

运行时间运行变异测试周期的运行成本可能是巨大的。当然,在大多数情况下,执行可以水平扩展,因为测试可以在多台机器上运行,或者可以通过使用更强大的机器进行垂直扩展。为了应用水平可扩展性,有必要在选择适当的变异测试工具时考虑这一点,并支持此类方法。还需要考虑提高测试运行时间的经典测试自动化技术。当测试运行一次时,内置到测试中的硬编码等待可能不会引起注意,但当扩展到数百或数千次执行时,就会成为一项重要的成本。在尝试引入变异测试之前,应优化自动化测试以提高性能。

分析两个相关的挑战是Oracle问题以及减少等价变异的问题。Oracle问题远非变异测试所独有,它适用于任何难以确定测试是否预期的测试领域。当无法杀死变异体时,就会发生这种情况,因为需要在测试中实现的断言太难实现。当软件的确定性较低,并且难以理解检测不到变异是否实际上是有意义时,也会发生这种情况。那么最大的挑战是什么:

最大的问题是测试oracle问题。对于小型项目来说,这不是什么大问题。然而,对于大型项目来说,变异会产生数千个变异体,其中数百个是有效的。目前还不清楚开发工程师应该如何处理它们——人工review这些显然是不切实际的。

减少等价变异的问题也很重要,也就是说,变异不会导致输出可观察变化。这可能是因为未执行过的僵尸代码;变异只改变软件的速度;或者变异只改变内部使用的数据,不影响最终输出。

让我们看一个等价的变异:

def foo(i): 
  return i + 1 + 0

一个潜在的等价变异的例子是删除“+ 0”。虽然这会改变正在测试的软件,但它不会改变输出,因为向一个数字加零没有任何实际效果。这正是关键所在,代码无关紧要,应该删除。

5. 变异测试工具

变异测试工具的种类繁多,这在一定程度上是因为它们与实现中使用的编程语言有着内在的联系。你通常不能使用为 C++ 设计的工具来编写 Java。选择一个支持底层技术栈、支持让你配置所需的变异启发式方法、与你的开发环境集成并支持并行和分布式执行的工具至关重要。使用这些工具可以简单到在你的构建配置中注入依赖项。选择和评估适合你的工具实际上比传统工具选择更重要。一个原因是这些工具将带有不同的内置默认操作符和策略。正如前面提到的,这些操作符和策略有效地决定了技术方法,并直接影响结果。该工具还可以确定如何扩展运行时执行,而选择一个支持有限的工具可能会导致不切实际的时间表。

然而,你需要考虑的不仅仅是变异工具:

作为一个实施者,我看到的更大的问题应该是如何无缝集成。如何将变异集成到现有的基础设施中:各种构建系统、测试框架、CI 管道、IDE 等

对于测试周期而言,还有很多工具。例如,Pitest,一个Java变异引擎;Cucumber插件允许你与Cucumber行为驱动开发集成。同样,SonarQube,一个流行的代码质量监控集,有插件允许你显示变异测试运行的详细结果。一些变异测试引擎还提供IDE插件,加速反馈循环,并允许你在代码上下文中查看结果。

6. 总结一下

本文主要是希望开阔大家的视野,以另一种视角来看测试覆盖率。虽然变异测试仅频繁应用在单元测试层面,但这些概念可以应用于整个软件质量保证实践。它不仅是一种评估自动化测试价值的有效方法,而且是一种了解代码复杂性的方法,以及定量了解代码质量和测试覆盖率的方法。这些概念也可以应用于代码、输入数据、环境和其他技术。

- END -


下方扫码关注 软件质量保障,与质量君一起学习成长、共同进步,做一个职场最贵Tester!

关注「软件质量保障」微信公众号

好文推荐

往期推荐

聊聊工作中的自我管理和向上管理

经验分享|测试工程师转型测试开发历程

聊聊UI自动化的PageObject设计模式

细读《阿里测试之道》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700303.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARM+FPGA+NVIDIA AI摄像头软硬件定制

拥有资深ISP图像技术团队,是英伟达、地平线等合作伙伴,我们的团队掌握目前市面上大部分车载平台的ISP图像画质服务能力,能自主开发图像ISP和增强算法。我们具有多名经验丰富光学设计专家,掌握车载模组光学设计能力,资深…

数据结构——链表——模板类实现双向链表——先完成再完美——持续更

链表:概念,实现,《数据结构》这里实现是基于模板的 C语言基础,指针,引用。模板。《CPrimer》有些进阶用法放在语言学习的目录 LeetCode应用,会更新在LeetCode150,目前这个系列先暂停&#xff0c…

遇见问题-VMware虚拟机打开运行一段时间后卡死

1.问题原因 因为Windows自带的虚拟化软件Hyper-V与VMware存在冲突。 2.关闭Hyper-V 1.打开【控制面板】-【程序和功能】-【启用或关闭Windows功能】3.关闭HV主机服务 1.右击计算机-》管理-》服务和应用名称-》服务-》找到HV主机服务-》右击属性停止服务 -》启动类型设置为禁…

NASA数据集——阿尔法喷气式大气实验二氧化碳和甲烷数据

Alpha Jet Atmospheric eXperiment Carbon Dioxide and Methane Data 阿尔法喷气式大气实验二氧化碳和甲烷数据 简介 Alpha Jet Atmospheric eXperiment (AJAX) 是美国国家航空航天局艾姆斯研究中心与 H211, L.L.C. 公司的合作项目,旨在促进对加利福尼亚、内华达…

asp.net core接入prometheus2-自定义指标

前提 了解一下asp.net core接入prometheus快速入门 https://blog.csdn.net/qq_36437991/article/details/139064138 新建.net 8空web项目 安装下面三个包 <PackageReference Include"OpenTelemetry.Exporter.Prometheus.AspNetCore" Version"1.8.0-rc.1&…

【软件设计师】计算机组成原理

1、数据的表示 1.1 进制转换 整型有4种进制形式&#xff1a; 1.十进制&#xff08;D&#xff09;&#xff1a; 都是以0-9这九个数字组成&#xff0c;不能以0开头。 2.二进制&#xff08;B&#xff09;&#xff1a; 由0和1两个数字组成。 3.八进制&#xff08;O&#xff09;&am…

Java的类路径究竟是什么?

回答 问了chatgpt这个问题&#xff0c;首先类路径的定义是&#xff1a; 是指一组路径&#xff0c;这些路径告诉Java虚拟机&#xff08;JVM&#xff09;和类加载器在哪里可以找到应用程序所需的类和资源文件。说白了就是在运行java程序的时候需要先将java源代码编译成class文件…

代码随想录——从前序与中序遍历序列构造二叉树(Leetcode105)

题目链接 递归 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

nginx + confd + etcd 实现nginx动态白名单,防止请求host篡改注入攻击

众所周知&#xff0c;浏览器发送到后台请求header中携带的host是可能被修改的&#xff0c;为了防止这件事情发生&#xff0c;就很有必要给后台设置host请求白名单了&#xff0c;本次将介绍nginx如何配置&#xff0c;以及结合confd和etcd实现动态配置。 1. http/https请求的host…

flink cdc mysql整理与总结

文章目录 一、业务中常见的需要数据同步的场景CDC是什么FlinkCDC是什么CDC原理为什么是FlinkCDC业务场景flink cdc对应flink的版本 二、模拟案例1.阿里云flink sql2.开源flink sql(单机模式)flink 安装安装mysql3.flink datastream 三、总结 提示&#xff1a;以下是本篇文章正文…

MFC扩展库BCGControlBar Pro v34.1新版亮点:日历和计划表等功能升级

BCGControlBar库拥有500多个经过全面设计、测试和充分记录的MFC扩展类。 我们的组件可以轻松地集成到您的应用程序中&#xff0c;并为您节省数百个开发和调试时间。 BCGControlBar专业版 v34.1已正式发布了&#xff0c;这个版本包含了对Windows 10/11字体图标的支持、功能区和…

huggingface 笔记:查看GPU占用情况

0 准备部分 0.1 创建虚拟数据 import numpy as npfrom datasets import Datasetseq_len, dataset_size 512, 512 dummy_data {"input_ids": np.random.randint(100, 30000, (dataset_size, seq_len)),"labels": np.random.randint(0, 1, (dataset_size…

PHP+Lucky+Baby母婴用品网站的设计与实现75554-计算机毕业设计项目选题推荐(附源码)

摘 要 近年来&#xff0c;随着移动互联网的快速发展&#xff0c;电子商务越来越受到网民们的欢迎&#xff0c;电子商务对国家经济的发展也起着越来越重要的作用。简单的流程、便捷可靠的支付方式、快捷畅通的物流快递、安全的信息保护都使得电子商务越来越赢得网民们的青睐。现…

中国低调海外巨头,实力超乎想象!

在全球化的浪潮中&#xff0c;中国公司正以前所未有的速度和规模走向世界。他们或许低调&#xff0c;但却实力非凡&#xff0c;在国际市场上掀起了一股不可小觑的“中国风暴”。今天&#xff0c;就让我们揭开那些在国外牛逼到爆炸的中国公司的神秘面纱&#xff0c;深度解析他们…

IP编址、进制转换、IP地址分类、变长子网掩码VLSM、无类域间路由CIDR

前言 网络层位于数据链路层与传输层之间。网络层中包含了许多协议&#xff0c;其中最为重要的协议就是IP协议。网络层提供了IP路由功能。理解IP路由除了要熟悉IP协议的工作机制之外&#xff0c;还必须理解IP编址以及如何合理地使用IP地址来设计网络。 IP编址 每个网段上都有两…

滤波电路应用笔记

滤波器 什么是滤波器&#xff1f; 滤波器是一种使某些频率或频带上的电信号通过而阻止其他信号通过的装置。 滤波电路的作用是尽可能减少脉动直流电压中的交流分量&#xff0c;保持其直流分量&#xff0c;降低输出电压的纹波系数&#xff0c;并使波形相对平滑。整流电路的输出…

商标注册申请名称的概率,多想名称选通过率好的!

近日给深圳客户申请的商标初审下来了&#xff0c;两个类别都下的初审&#xff0c;和当初的判断基本一致&#xff0c;普推知产老杨当时沟通说需要做担保申请注册也可以&#xff0c;后面选择了管家注册&#xff0c;最近大量的帮客户检索商标名称&#xff0c;分享下经验。 两个字基…

PC端应用订阅SDK接入攻略

本文档介绍了联想应用联运sdk接入操作指南&#xff0c;您可在了解文档内容后&#xff0c;自行接入应用联运sdk。 1. 接入前准备 1. 请先与联想商务达成合作意向。 2. 联系联想运营&#xff0c;提供应用和公司信息&#xff0c;并获取商户id、app id、key&#xff08;公私钥、…

【设计模式深度剖析】【4】【结构型】【组合模式】| 以文件系统为例加深理解

&#x1f448;️上一篇:适配器模式 设计模式深度剖析-专栏&#x1f448;️ 目 录 组合模式定义英文原话直译如何理解&#xff1f; 3个角色UML类图代码示例 组合模式的优点组合模式的使用场景示例解析&#xff1a;文件系统 组合模式 组合模式&#xff08;Composite Pattern&a…

【经典论文阅读10】MNS采样——召回双塔模型的最佳拍档

这篇发表于2020 WWW 上的会议论文&#xff0c;提出一种MNS方式的负样本采样方法。众所周知&#xff0c;MF方法难以解决冷启动问题&#xff0c;于是进化出双塔模型&#xff0c;但是以双塔模型为基础的召回模型的好坏十分依赖负样本的选取。为了解决Batch内负样本带来的选择性偏差…