Go语言模糊测试

前言

在Go 1.18开始提供了Fuzzing能力的支持,testing包在我们常见的T B类型之外新增了F的类型,用于支持模糊测试。

Fuzzing Test

日常测试代码的时候我们经常使用table driven test的方式来构造一组输入和预期的结果,之后调用我们的待测函数,检查结果是否和我们的预期匹配,也就是我们平常说的Mock数据

这就引出了一个问题,这个table要多大呢?

通常大家都只是写几个【正常】的case 几个【异常】的case
但是这些样例其实是不够的,比如一些异常值、corner case,可能无法处理,或者可能有程序挂掉、安全问题等等

而fuzzing test的作用就是帮我们自动生成输入数据,以下是维基百科对于fuzzing test的定义

Fuzzing is a technique where you automagically generate input values for your functions to find bugs

模糊测试能够【持续】、【自动】地生成一系列【半随机】的数据作为待测函数的输入,来找到程序里隐藏的bug,对于边界case能够很好的验证。模糊测试中的输入不是由人工指定的,而是自动生成的随机数据,所以可以规避掉人工主观判断造出来的数据。

模糊测试通常可以不依赖于开发测试人员定义好的数据集,取而代之的则是一组通过数据构造引擎自行构造的一系列随机数据。 模糊测试会讲这些数据作为输入提供给待测程序,并且监测程序是否出现panic、断言失败、无限循环,或者其他的异常情况

这些通过数据构造引擎生成的数据被称为语料(corpus) ,另外模糊测试其实也是一种持续测试的手段,因为如果不限制执行的次数或者执行的最大时间,它就会一直不停的执行下去

Go模糊测试

让我们来看看一个Golang实现的模糊测试长什么样

签名部分:从常见的func TestXxx(t *testing.T) 变成了func FuzzXxx(f *testing.F)

seed corpus:一组用户提供的语料,fuzzing引擎会使用这个语料来生成随机数据。其实就是一个样本,之后引擎就知道要生成什么类型的随机数据了

Fuzzing arguments: 接受*testing.t和想要随机生成的数据类型

模糊测试的要求

  • 模糊测试必须是一个名称类似于FuzzXxx的函数,仅接受一个*testing.F参数,无返回值
  • 模糊测试必须在*_test.go中运行
  • Fuzz target(模糊目标)必须是对(testing.F).Fuzz的方法调用,参数是一个函数,并且这个函数的第一个参数是tesing.T,然后是模糊参数(fuzzing argument),没有返回值
  • 一个模糊测试中必须只有一个模糊目标
  • 所有种子语料库(seed corpus)必须具有与模糊参数相同的类型,顺序相同
  • 模糊参数只能是以下的类型
go 复制代码
string, []byte
int, int8, int16, int32/rune, int64
uint, uint8/byte, uint16, uint32, uint64
float32, float64
bool

需要注意的一点是,在Go执行的过程中,多个fuzzing target是并行来处理的,底层会有多个worker,调度的顺序也不一定,所以不能做持久化,也不能依赖一些全局状态,不要尝试改变入参

运行模糊测试

我们依然可以使用go test命令来跑模糊测试,只是需要加上一个-fuzz=FuzzTestName的选项。同时这个包下所有其他类型的test都会优先于模糊测试执行,毕竟比较耗费资源,随机数据生成是有样本的。

执行结果如下

yaml 复制代码
~ go test -fuzz FuzzFoo
fuzz: elapsed: 0s, gathering baseline coverage: 0/192 completed
fuzz: elapsed: 0s, gathering baseline coverage: 192/192 completed, now fuzzing with 8 workers
fuzz: elapsed: 3s, execs: 325017 (108336/sec), new interesting: 11 (total: 202)
fuzz: elapsed: 6s, execs: 680218 (118402/sec), new interesting: 12 (total: 203)
fuzz: elapsed: 9s, execs: 1039901 (119895/sec), new interesting: 19 (total: 210)
fuzz: elapsed: 12s, execs: 1386684 (115594/sec), new interesting: 21 (total: 212)
PASS
ok      foo 12.692s

Fuzzing test的局限性,在单元测试中因为测试输入是固定的,所以可以和把得到的结果和预期结果进行比较来判断执行结果是否与预期相符合。

但是在使用fuzzing的时候,我们无法预测输出结果是什么,因为测试的输入除了我们代码只能给指定的用例之外,还有fuzzing随机生成的输入,所以我们无法提前知道预期结果是什么。

推荐阅读

当说到云原生时,我们究竟在谈论什么? - 掘金

不太熟悉Git? 不妨看看这篇文章 - 掘金

一文搞定常见分布式事务实现 - 掘金

你真的理解分布式理论吗? - 掘金

深入了解异地多活 - 掘金

02.K8S架构详解 - 掘金

01.你为什么需要学习K8S - 掘金

相关推荐
哎呦没29 分钟前
大学生就业招聘:Spring Boot系统的架构分析
java·spring boot·后端
_.Switch1 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
杨哥带你写代码2 小时前
足球青训俱乐部管理:Spring Boot技术驱动
java·spring boot·后端
AskHarries3 小时前
读《show your work》的一点感悟
后端
A尘埃3 小时前
SpringBoot的数据访问
java·spring boot·后端
yang-23073 小时前
端口冲突的解决方案以及SpringBoot自动检测可用端口demo
java·spring boot·后端
Marst Code3 小时前
(Django)初步使用
后端·python·django
代码之光_19803 小时前
SpringBoot校园资料分享平台:设计与实现
java·spring boot·后端
编程老船长3 小时前
第26章 Java操作Mongodb实现数据持久化
数据库·后端·mongodb
IT果果日记4 小时前
DataX+Crontab实现多任务顺序定时同步
后端