鉴源论坛 · 观模丨浅谈随机测试

news2024/12/23 17:54:32

作者 | 黄杉 华东师范大学软件工程学院博士

          苏亭 华东师范大学软件工程学院教授

首发 | 鉴源论坛 · 观模

01

 什么是随机测试

(Random Testing)

随机测试是一种使用随机、相互独立的程序输入来对计算机程序进行测试的黑盒软件测试(在完全忽略程序内部实现细节的情况下进行测试)技术。在处理完随机且独立的程序输入后,程序输出的结果将会和软件规格说明(software specifications)中所描述的软件行为进行比对来判断该测试是否通过。

随机测试的核心思想接近于无限猴子定理[1](The Infinite Monkey Theorem),所以随机测试也被称为Monkey Testing。无限猴子定理是来自Émile Borel的一本出版于1909年的概率相关的书籍,其中描述了这样一个场景:当一只猴子在打字机键盘上不限时间地随机敲击,它可能输出任何给定文章,例如莎士比亚的完整作品,并且这种可能性随着时间的增长会不断地接近100% 。换用测试的语言来描述则是测试程序通过不断地生成测试输入,其能完整测试整个程序并寻找到程序中异常的可能性会不断增大。

02

早期的随机测试

最早对随机测试技术的使用可以追溯到上个世纪五十年代,那时的数据还存储在穿孔卡片(Punched Card)上。程序员会将扔进垃圾桶中的卡片或者标记有随机数字的卡组作为计算机程序的输入来进行随机测试。

当随机测试被广泛认定为测试程序的最差方式时,Duran和Ntafos两人在1981年正式地对使用随机测试技术对程序进行测试的有效性进行了调研,结果表明相对于系统化的测试技术,随机测试是一个成本低收益高的替代品。

后来在1983年,苹果公司的Steve Capps开发了一款名为“The Monkey”的随机输入生成工具用来对传统的MacOS应用进行测试。他对工具的命名就是化用了无限猴子定理。

1991年,一款名叫 “crashme” 的工具发布。这款工具意在通过随机执行带有随机参数的系统调用来测试Unix以及类Unix操作系统的鲁棒性。

03

随机测试的优缺点

3.1 优点

(1)容易实现和使用。随机测试并不需要知晓程序细节,并且输入也通过随机生成。

(2)对程序不存在偏见。由于随机测试的输入都是随机生成的,不存在人为因素影响,也就不会因为对程序某一部分信任而忽略掉潜在的漏洞。

(3)能快速查找漏洞。随机测试的测试速度快,通过快速和大量的测试,能够在短时间内找到大量的候选漏洞(对漏洞的确认还需要人工参与)。

3.2 缺点

(1)寻找漏洞的精度不高由于随机测试的完全随机性,寻找到的漏洞很可能是一些无关紧要的错误。

(2)过于随机导致对程序的代码覆盖率不高。大部分人认为对程序的测试过于依赖随机,不如通过人工白盒测试的方式来更精确地测试程序。

04

随机测试进阶

模糊测试(Fuzzing)

在1988年的一个风雨交加的夜晚,威斯康星大学的Barton Miller教授在自己的公寓中通过一条电话线连接他在学校中的计算机。暴风雨引发了电话线中的信号错乱,以至于所连接的Unix终端不断接收到糟糕的命令输入,最终导致了系统崩溃。频发的崩溃使这位讲授操作系统课程的教授感到惊讶,因此他脑海中浮现了一个对Unix系统进行鲁棒性测试的念头。于是他在给学生的课程作业中写道:

The goal of this project is to evaluate the robustness of various UNIX utility programs, given an unpredictable input stream. This project has two parts. First, you will build a fuzz generator...  Second, you will take the fuzz generator and use it to attack as many UNIX utilities as possible, with the goal of trying to break them... [2]

教授在作业中要求学生开发一个模糊生成器(fuzz generator),这个生成器可以产生不可预测的输入流,然后将这些杂乱的输入给到Unix系统设施,然后试图攻陷这些设施并找到和分析引发错误的随机输入和原因。这就是模糊测试的诞生,教授在作业中使用的fuzz一词也就被用来命名这一技术。

从上文可以看到模糊测试在诞生之初和随机测试十分相似,都是通过随机的输入来对计算机程序进行功能行为测试。下面的Python代码片段给出了一个最简单的模糊器(fuzzer)例子。这个模糊测试器接收三个参数:最大长度(max_length)、字符的ASCII码起始值(char_start)以及字符的ASCII码从起始到结束的范围(char_range)。该模糊器将生成一个长度为max_length的包含ASCII码在[char_start, char_start + char_range)范围内的字符串。

图 1

所以最原始的模糊测试和随机测试拥有相同的优缺点。其中最显著的问题就是由于其完全的随机性,寻找到的程序错误过于刁钻。可能找到的程序错误只是因为错误的输入导致而和程序本身实现无关,或者程序使用人员根本就不会使用像模糊测试器生成的输入,所以不会在软件设计的考虑范畴之内,甚至模糊测试根本就没有测试到程序的主要功能。

无论如何模糊测试还是有其可取之处的(尤其是测试速度快、易于实现),所以后来的研究者们不断想方设法地,尤其是针对如何更好地生成测试输入方面去提高模糊测试的精度(找到的错误确实是和软件规范说明或预期设想行为不符)和深度(能更多地去测试程序的主要功能)来完善模糊测试的实用性。实现这些目标的主要方法就是通过一些静态(基于覆盖率、基于变异)或动态(基于搜索、基于语法)的方式给模糊器提供额外的辅助信息来帮助模糊器更高效地生成、更有效地测试输入,而不再是完全随机,这也促使模糊测试从黑盒测试向灰盒测试进行转变。下文会进行具体介绍。

现在的模糊测试技术可以有几种划分方式(不限于此):

· 一种模糊测试技术可以是基于生成(generation-based)的或者基于变异(mutation-based),取决于它是在没有任何参考的情况下生成随机输入,还是在现有输入的基础上进行修改,也就是所谓的变异;

· 一种模糊测试技术可以是愚笨的(dumb)或者聪明的(smart),取决于它是否对测试输入的结构敏感;

· 一种测试技术可以是白盒、灰盒或者黑盒(基本上不再使用),取决于它是否对程序结构信息或者程序运行信息敏感。

目前最流行的模糊测试工具主要有AFL以及AFL的扩展系列,如AFLFast、AFL++、AFLGo等。

4.1 基于覆盖率的模糊测试(Coverage-Based Fuzzing)

对于如何提高模糊测试精度和深度的探索,其中一种是利用了代码覆盖率[3](code coverage)这一概念。代码覆盖率包括函数覆盖率(function coverage)、语句覆盖率(statement coverage)、边覆盖率(edge coverage)以及条件覆盖(condition coverage)率等多种覆盖准则,这些覆盖率都在一定程度上反映了测试用例对于程序代码的测试程度,即代码覆盖率越高,测试用例对代码的测试程度越高。近期的一项工作[4]也观察到模糊测试技术的代码覆盖率和能找到程序中的错误具有强相关性。

下面的Python代码片段将给出简单的例子。当输入inp为一个正数的时候,程序执行过程中将会执行第 2 行和第 3 行的代码语句,则语句覆盖率为 2 / 6 = 33.3%。另外对于条件覆盖率来说,整个函数中函数有三个 if 条件语句,每一个 if 条件语句都有真假两种情况,则根据组合原理该函数共有 6 个条件分支。在上述情况下,程序执行过程中只有第一个 if 条件语句为真的分支被执行,则条件覆盖为 1 / 6 = 16.7%。对于输入 inp 为零和负数的情况,语句覆盖为 3 / 6 = 50% 和 4 / 6 = 66.7%,条件覆盖率为 2 / 6 = 33.3% 和 3 / 6 = 50%。

图 2

在模糊测试中对于覆盖率的利用,主要是在测试用例的生成过程中。模糊器首先生成一定个数的随机输入,这些输入被称为种子(seed)。接着模糊器将这些种子输入程序,回收程序执行的结果和预先选定的覆盖率指标。接下来模糊器会根据覆盖率高低,将覆盖率低的种子丢弃,将覆盖率高的种子保留并对这些种子进行操作生成一批新种子再作为输入运行程序。重复上述过程到覆盖率不能够更进一步提高时,终止测试。

4.2 基于变异的模糊测试(Mutation-Based Fuzzing)

由于最初的模糊器完全靠随机生成程序输入,模糊测试很难生成出符合程序要求的合法输入,以至于很难测试到程序的核心功能,同时这也是代码覆盖率极低的一个原因。于是基于变异的模糊测试被提出来解决这个问题。

变异的核心思想是对现有的种子(种子可以合法也可以不合法,但大多数情况下会使用合法的种子,这样通过变异得到的种子后代质量较高)以及通过变异得到种子后代进行操作来生成测试输入。具体的变异操作需要测试人员执行制定。假如针对一个计算机程序的一个合法的程序输入为“3+0”,那么在指定变异操作为随机增加、删除和替换字符串中的某一个字符这三种操作时,经过变异之后的输入就有多种可能,如“3 + - 0”、“3 +”、“3 / 0”。将这些通过变异得到的种子后代扔入程序中运行,这就是基于变异的模糊测试。

变异操作可以被设计为更加复杂精细的过程,例如结合其他种子质量评估指标进行变异或者进行某种针对性变异操作。上一小节末尾描述的将变异操作和覆盖率指标进行结合来反复对程序进行测试,这样可以很好地利用这两种方法的优势,从而增强模糊测试的有效性。著名的模糊测试工具AFL就是基于这样的思路开发的。

4.3 基于搜索的模糊测试(Search-Based Fuzzing)

基于搜索的模糊测试主要依赖于搜索算法。搜索算法也被称为启发式算法(heuristic algorithm),其核心思想是通过某些程序信息来启发和引导算法执行。这些算法的灵感大多是来自自然界的现象,如模拟退火算法和本小节会介绍的遗传算法。而它们之所以被称为搜索算法,是因为执行这些算法可以在较大的搜索空间中比随机算法或遍历算法更高效。同样以上一小节的计算机程序输入为例,模糊器对该程序进行模糊测试本质上就是在不断地探索其输入空间,该输入空间中包含了任意长度的合法或不合法的表示四则运算表达式的字符串。想要通过测试来挖掘出程序中隐藏的缺陷,就是在输入空间中搜索到特定的输入使得该程序在运行时出现异常行为;想要满足更广的程序覆盖率,就是在输入空间中搜索到特定的输入使得让该程序运行时执行更多的程序语句。

因此搜索算法也就自然而然地与模糊测试结合在了一起,来使模糊器生成更优质的程序测试输入。下面将对基于结合代码覆盖率的遗传算法的模糊测试进行简单的介绍。

我们构建一个简单函数 fun2,该函数将判断特定字符是否存在于输入字符串中,然后对应分支返回一个整型数字。

图 3

在这个例子中我们给定模糊器的初始种子,为“axxx”,“xxxb”、“xxxc”和“xxxd”。我们首先将这些种子作为输入来运行这个函数,得到每个种子的语句覆盖数量,分别是 3 、2 、2、2 。输入“axxx”是可以让程序执行第 2、3 和 8 行语句,而后三个输入只能执行第 2 和 8 行语句。第一轮测试已经结束,这时我们根据种子的语句覆盖数量来生成下一次测试输入集合,具体过程为从种子中选取语句覆盖数量最多的两个作为亲代来进行交叉变异(模拟自然界的遗传现象)。由于后三个种子的数据覆盖数量都为 2 ,则在选择时会随机选取。假设“axxx”和“xxxb”得到了选择,则继续对这两个种子进行交叉变异,此处交叉变异定义为交换两个种子的右半部分子串,即得到的子代为“axxb”和“xxxx”。重复这样的选择并交叉变异的过程直到子代数量等于初始种子数量。假定经过上述过程我们最后得到了“axxb”、“xxxx”、“axxc”和“xxxx”这四个子代,然后就继续重复整个执行过程,也就是将这些子代输入程序继续运行遗传算法来生成更加优质的测试输入,最终提高代码覆盖率和异常检测能力。

从上述例子中可以看到在子代中的“axxb”不仅将原本“axxx”的语句覆盖数量从 3 提升到了 4,并且能更深入地探索整个函数中的条件分支。但可以看到对于上述例子中假设得到子代整个算法已经无法再有进步了,因为这些子代不论怎么交叉变异也无法得到一个包含abc三个字母的字符串。在实际工业生产环境中算法本身会更加复杂,测试种子会经过精心生成和挑选,同时纳入更多指标进行算法引导,对交叉变异的过程也不会只是简单地字符串交换。

4.4 通过文法进行模糊测试(Fuzzing with Grammars)

当程序的输入具有一定规范和结构的(比如数据库或者API的输入),人们开始尝试通过文法(Grammar)来帮助模糊器生成合法规范的测试输入,属于前面提到的基于生成(Generation-based)的模糊测试技术。

下面展示了一个简单的文法,该文法描述的是含有小数或整数的加减乘除的四则运算表达式,如 (1 + 2) * (3.4 / 5.6 - 789) 。使用该文法,从 <start> 非终止符(non-terminal)开始展开,最终就可以得到一个可用于测试计算程序的合法的四则运算表达式。

图 4

对于表达式  (1 + 2) * 3 的部分推导过程如下,过程中遵循最左推导。推导中剩下的部分读者可以自行尝试完成。

图 5

通过这样来产生测试输入相比于纯随机的方式不仅产生的种子质量高,并且符合程序输入规范,能够节省无效测试用例的时间开销从而提高测试效率。

05

总结

随机测试为软件测试提供了一个在黑盒情况下快速和大量地测试程序的全新思路,其进阶版模糊测试更是在经过包括上述基于覆盖率、基于变异、基于搜索以及文法辅助在内的多种方法的增强之后,成为了当前工业环境下软件测试的主流选择,被广泛应用于人工智能测试、自动驾驶系统测试、数据库系统测试、API测试等各种测试场景。虽然克服了随机测试和模糊测试诞生之初的缺陷和问题,当下的模糊测试仍然有待提高进步,例如对模糊测试过程中对触发的程序错误的类型进行识别、整理和分类,以及对引发错误的根源诱因的分析等。学界和工业界也对传统静态分析工具如符号执行技术和模糊测试技术相结合的道路在不断地探索。

参考资料:

[1] “Infinite Monkey Theorem.” In Wikipedia, September 1, 2022. https://en.wikipedia.org/w/index.php?title=Infinite_monkey_theorem&oldid=1107846001.

[2] Bart Miller. 1988.  https://pages.cs.wisc.edu/~bart/fuzz/CS736-Projects-f1988.pdf

[3] “Code Coverage.” In Wikipedia, July 7, 2022. https://en.wikipedia.org/w/index.php?title=Code_coverage&oldid=1096923322.

[4] Marcel Böhme, László Szekeres, and Jonathan Metzman. 2022. On the reliability of coverage-based fuzzer benchmarking. In Proceedings of the 44th International Conference on Software Engineering (ICSE '22). Association for Computing Machinery, New York, NY, USA, 1621–1633. https://doi.org/10.1145/3510003.3510230

[5] “The Fuzzing Book.” Accessed November 5, 2022. https://www.fuzzingbook.org/.

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

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

相关文章

疫情联防联控解决方案-最新全套文件

疫情联防联控解决方案-最新全套文件一、建设背景1、疫情防控数据涉及多方&#xff0c;共享难2、疫情数据使用实时性和准确性差3、敏感信息容易泄露和滥用4、建设成本高&#xff0c;后续扩展性弱二、思路架构三、建设方案四、获取 - 疫情联防联控全套最新解决方案合集一、建设背…

OA系统必备的五个基本要素

如果你正在寻找可以将工作流程提升到一个新水平的OA系统&#xff08;或办公自动化系统&#xff09;&#xff0c;请查看其是否具备以下五个基本功能。 1、简单的工作流设计器 一个现代的OA系统应该从业务用户的角度出发。 当你坐下来试用一个OA系统时&#xff0c;先从制定自…

spring中使用getBean获取ioc容器创建的对象常见异常

1、获取bean对象的三种基本方式 0、前提准备 <?xml version"1.0" encoding"UTF-8"?> <beans xmlns"http://www.springframework.org/schema/beans"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocat…

线性代数 --- 投影Projection 五(投影矩阵的性质)

投影矩阵的性质 1&#xff0c;投影矩阵不可逆。 行列式的值为0&#xff0c;条件数无穷大&#xff0c;说明该矩阵不可逆是一个奇异矩阵singular matrix。 同样&#xff1a;行列式的值为0&#xff0c;条件数趋近于无穷大&#xff0c;说明该矩阵不可逆是一个奇异矩阵singular matr…

C# async / await 用法

目录 一、简介 二、异步等待返回结果 三、异步方法返回类型 四、await foreach 五、Task.Delay 结束 一、简介 await 运算符暂停对其所属的 async 方法的求值&#xff0c;直到其操作数表示的异步操作完成。 异步操作完成后&#xff0c;await 运算符将返回操作的结果&…

遨博机械臂——末端工具ROS驱动

文章目录知识目标1. 机械臂末端工具&#xff08;EOAT&#xff09;2. 电动夹爪3. 气动吸盘参考知识目标 学习机械臂常用末端工具构成&#xff1b;学习aubo机械臂安装电动夹爪及启动吸盘的方法&#xff1b;学习电动夹爪及气动吸盘ROS驱动的使用方法。 1. 机械臂末端工具&#x…

【附源码】计算机毕业设计JAVA校园社团管理平台

【附源码】计算机毕业设计JAVA校园社团管理平台 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; JAVA my…

“3%”与“低个位数”,暴雪为什么要跟网易玩数字游戏?

北京时间11月17日上午&#xff0c;暴雪娱乐发布声明称&#xff0c;由于同网易的现有授权协议将在2023年1月23日到期&#xff0c;将暂停在中国大陆的大部分暴雪游戏服务&#xff0c;包括《魔兽世界》《炉石传说》《守望先锋》《星际争霸》《魔兽争霸Ⅲ&#xff1a;重置版》《暗黑…

[iOS]砸壳

进行砸壳&#xff0c;需要有台越狱手机。如何越狱&#xff0c;参考前一篇“[iOS]手机越狱”。 没有越狱设备的话&#xff0c;可以去某宝寻求帮助&#xff0c;有帮忙砸壳。 1.添加源 打开Cydia软件&#xff0c;软件源中选择编辑&#xff0c;添加源https://cydia.iphonecake.co…

文件预览服务器kkfileview安装部署(linux 版)

1、安装 LiberOffice 安装包 命令下载 wget https://kkfileview.keking.cn/LibreOffice_7.1.4_Linux_x86-64_rpm.tar.gz tar -zxvf LibreOffice_7.1.4_Linux_x86-64_rpm.tar.gz cd LibreOffice_7.1.4.2_Linux_x86-64_rpm/RPMS yum install -y *.rpm 2、验证office是否安装成功…

【MySQL】MVCC详解与MVCC实现原理(MySQL专栏启动)

&#x1f4eb;作者简介&#xff1a;小明java问道之路&#xff0c;专注于研究 Java/ Liunx内核/ C及汇编/计算机底层原理/源码&#xff0c;就职于大型金融公司后端高级工程师&#xff0c;擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。 &#x1…

Vue2 Element | 一文带你快速搭建网页界面UI

&#x1f451; 博主简介&#xff1a;    &#x1f947; Java领域新星创作者    &#x1f947; 阿里云开发者社区专家博主、星级博主、技术博主 &#x1f91d; 交流社区&#xff1a;BoBooY&#xff08;优质编程学习笔记社区&#xff09; 前言&#xff1a;在学习本篇文章内容…

Cholesterol胆固醇丨艾美捷Cholesterol胆固醇化学性质

胆固醇是由甾体部分和一条长的侧链组成。人体中胆固醇的总量大约占体重的0.2%&#xff0c;每100克组织中&#xff0c;骨质约含10毫克&#xff0c;骨骼肌约含100毫克&#xff0c;内脏多在150~250毫克之间&#xff0c;肝脏和皮肤含量稍高&#xff0c;约为300毫克。脑和神经组织中…

【JVM学习笔记】JVM内存区域定义与内存结构

目录定义和说明JVM内存区域的定义内存区域说明堆说明非堆-方法区说明堆栈的区别HotSpot虚拟机JVM线程独占内存程序计数器&#xff1a;Program Counter RegisterJava虚拟机栈&#xff1a;Java Virtual Machine Stack本地方法栈&#xff1a;Native Method StackJVM共享内存Java堆…

Arduino与Proteus仿真实例-密码门禁控制仿真

密码门禁控制仿真 1、应用介绍 本文将演示如何实现密码门禁控制逻辑仿真。 此次仿真主要涉及如下内容: 密码输入、更新、验证门禁控制逻辑此次仿真将使用继电器和直流电机作为电子门禁元件仿真器件。 在前面的文章中,对密码输入、更新、验证、储存,做了详细的仿真,请参…

API:低代码平台的秘诀

应用编程接口 (API) 是应用程序以可编程格式访问其关键能力和功能的一种方式&#xff0c;从而其他应用程序可以利用它们。API 本质上支持应用程序之间的无缝数据流&#xff0c;使开发人员能够在应用程序中添加更多功能&#xff0c;而无需依赖大量编码。 举一个简单的例子。 您…

实战!接口优化的18种方案

前言 大家好&#xff0c;我是捡田螺的小男孩。 之前工作中&#xff0c;遇到一个504超时问题。原因是因为接口耗时过长&#xff0c;超过nginx配置的10秒。然后 真枪实弹搞了一次接口性能优化&#xff0c;最后接口从11.3s降为170ms。本文将跟小伙伴们分享接口优化的一些通用方案…

maven如何手动添加jar包到本地仓库

1 下载需要添加的jar包 可以在maven库中查找下载&#xff0c;也可以在对应官网下载 maven库网址 2 第二步&#xff1a;将下载的jar包放到指定位置&#xff08;位置自己指定&#xff09; 3 第三步&#xff1a;配置本地maven库 &#xff08;1&#xff09;首先检查本地maven库…

结构优化软件SolidThinking Inspire的自学攻略

作者&#xff1a;孙一凡&#xff0c;仿真秀专栏作者 2004年上大学那会&#xff0c;ANSYS软件推广应用还没现在这么广泛&#xff0c;有个老师接项目就是用ANSYS计算&#xff0c;觉得很是高大上&#xff01;ABAQUS还是一个小众软件&#xff0c;甚至一本参考资料书籍都买不到。短…

前端一面经典react面试题(边面边更)

react 的虚拟dom是怎么实现的 首先说说为什么要使用Virturl DOM&#xff0c;因为操作真实DOM的耗费的性能代价太高&#xff0c;所以react内部使用js实现了一套dom结构&#xff0c;在每次操作在和真实dom之前&#xff0c;使用实现好的diff算法&#xff0c;对虚拟dom进行比较&…