Go 中的随机性测试

news2024/11/24 23:07:55

👇我在这儿 

这是关于 Go 语言模糊测试的四部分教程系列的第一部分:

1、Go 语言中的随机测试

2、Go 语言中的模糊测试

3、写一个 Go 语言的模糊测试目标(即将推出)

4、通过模糊化发现漏洞(即将推出)

为我们的 Go 程序选择好的测试用例有点看运气。有时我们很幸运找到一个错误的输入或者甚至造成崩溃,但通常来说,随机选择输入不是一个发现 bug 的好方法。

或者说有可能吗?如果我们把这个想法发挥到极致,使用很多不同的输入呢?比如一百万个,或者十亿个。有这么多的输入,找到一个触发问题的奇怪值的可能性变得相当大。

听起来太多重复的输入工作了?我同意你的观点,所以让计算机来做这项工作吧。毕竟,那不就是它们的用途吗?

生成随机测试的输入值

好的,我们知道如何在 Go 中生成随机数:我们可以使用 math/rand(或者,对于更高级别的随机性,bitfield/qrand)。让我们试试看。

假设我们有一对函数 Encode 和 Decode。它们确切地做什么并不重要,但我们可以假设如果你对某些东西进行了 Encode,然后对结果进行 Decode。只要这些函数正常工作,你应该得到你最初的数据。

这里有一个测试,它生成一个介于 0 和 9 之间的随机整数,并将其通过两个函数 Encode 和 Decode 进行 往返处理:

import "math/rand"


func TestEncodeFollowedByDecodeGivesStartingValue(t *testing.T) {
    t.Parallel()
    input := rand.Intn(10)
    encoded := codec.Encode(input)
    t.Logf("encoded value: %#v", encoded)
    want := input
    got := codec.Decode(encoded)
    // after the round trip, we should get what we started with
    if want != got {
        t.Errorf("want %d, got %d", want, got)
    }
}

你可能会担心,如果这个值是 真正 随机的,那么我们可能会得到一个不稳定的测试结果。如果 Encode 或 Decode 中存在某些输入触发的 bug,那么像这样的测试有时会通过,有时会失败,对吗?

这确实是一种可能性。避免这种情况的一种方法是使用某个固定值对随机数生成器进行 种子(seed)处理:这样,生成的序列将始终相同,使我们的测试具有确定性。

例如,我们可以编写以下代码,它将为测试创建一个新的随机生成器,种子的值为 1:

var rng = rand.New(rand.NewSource(1))

我们不必使用 1 作为种子;任何固定值都可以。关键是,给定某个特定的种子,调用 rng.Intn 将始终产生相同的值序列:

fmt.Println(rng.Intn(10)) // 1
fmt.Println(rng.Intn(10)) // 7
fmt.Println(rng.Intn(10)) // 7
fmt.Println(rng.Intn(10)) // 9
fmt.Println(rng.Intn(10)) // 1

如果我们确实希望每次运行测试时都获得不同的序列,那么我们可以使用一些 不固定 的种子值。例如,当前的时钟时间:

var rng = rand.New(rand.NewSource(time.Now().Unix()))

对一组已知的输入进行随机置换

使用随机性的一个好方法,不会导致不稳定的测试或需要手动设置随机数生成器的种子,是对一组输入进行 排列 ——即以某种随机顺序重新排列它们。

例如,以下代码生成一个包含从 0 到 99 的整数的切片,以随机顺序排序:

inputs := rand.Perm(100)
for _, n := range inputs {
    ... // test with input n
}

rand.Perm(100) 生成的 100 个整数序列本身并不是随机的,因为从 0 到 99 的每个值都将恰好出现一次。这对于随机 选择 的数字来说是不成立的,因为某些值会多次出现,而其他值则不会出现。

相反,这个序列是随机 排列 的(即随机排序)。这就像洗牌一副牌:你知道每张牌仍然会出现恰好一次,只是不知道出现的顺序。

与 rand.Intn 一样,每次测试运行的结果都会不同,除非你创建一个使用已知种子初始化的自己的随机数生成器。

基于属性的测试

随机性可以是发现有趣的新测试用例的好方法,这些测试用例可能是你自己想不到的。例如,如果您的函数接受整数,您可能已经尝试使用 1、5、7 等进行测试。您可能没有想到尝试将 零 作为输入,但随机生成器很可能会在某个时候产生它。如果您的函数在给定零时出现问题,那么这是您肯定想知道的。

通常,好的测试人员擅长提出打破程序的输入,因为 程序员 没有考虑到它们。随机性可以帮助这个过程。

随机测试输入的一个问题可能已经出现在您的脑海中:如果我们事先不知道要使用什么输入,我们就无法知道期望的结果是什么。

例如:

func TestSquareGivesCorrectResult(t *testing.T) {
    t.Parallel()
    input := rand.Intn(100)
    got := square.Square(input)
    want := ... // uh-oh, what to put here?

这里的 want 值是什么?我们不知道,因为我们不知道在测试运行时 input 的值将是什么,以及它的平方将是什么。如果我们知道 input 将是 10,那么我们可以让测试期望答案为 100,但我们 不知道。我们陷入了困境。

我们不想在测试中尝试 计算 期望结果,因为很明显我们可能会计算错误。在最恶劣的情况下,我们可能会在测试中使用与 系统 中相同的代码路径来计算它,因此我们最终什么也没测试到。

如果我们无法预测对于给定的输入 Square 的 确切 结果,那么有没有任何一般性的描述呢?

实际上,有一些我们可以说的东西:它不应该是负数!无论输入是什么,如果 Square 返回一个负数,那么就有问题了。因此,尽管如果系统正确,我们无法预测 Square 的 确切 结果,但我们仍然可以确定它应该具有的一些 属性。

因此,我们可以编写一个测试,调用 Square 并使用许多不同的输入,检查结果是否为负数:

func TestSquareResultIsAlwaysNonNegative(t *testing.T) {
    t.Parallel()
    inputs := rand.Perm(100)
    for _, n := range inputs {
        t.Run(strconv.Itoa(n), func(t *testing.T) {
            got := square.Square(n)
            if got < 0 {
                t.Errorf("Square(%d) is negative: %d", n, got)
            }
        })
    }
}

这种方法有时被称为 基于属性的测试,以区别于到目前为止我们一直在做的 基于示例的测试。

另一种思考方法是,基于属性的测试描述系统的行为,不是根据确切的值,而是根据 不变量:不论输入是什么,结果中不会改变的东西。例如,对于 Square,其结果应该始终为正数。

基于属性的随机测试有助于解决函数可能仅适用于我们考虑的特定示例的问题。虽然我们会随机 生成 输入,但一旦我们找到一些触发错误的值,它就应该成为常规基于示例的测试的一部分。

我们可以通过在表格测试的输入集中手动添加这些值来实现这一点,但没有必要。Go 提供了一种自动将随机生成的破坏性输入转换为静态测试用例的方法,称为 模糊测试。

原文地址:Random testing in Go — Bitfield Consulting

原文作者:John Arundel

本文永久链接

translator/w18_Random_testing_in_Go.md at master · gocn/translator · GitHub

译者:zxmfke

校对:fivezh



f7be39bb38269729c21bcc6ac4e54d4f.jpeg

快点击阅读原文报名吧~~

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

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

相关文章

chatgpt赋能python:Python字符串首字母大写的方法,让你的SEO效果更佳

Python字符串首字母大写的方法&#xff0c;让你的SEO效果更佳 在许多编程语言中&#xff0c;字符串都是一种基本的数据类型。在Python中&#xff0c;字符串是一个非常重要的数据类型&#xff0c;因为在很多情况下&#xff0c;它被用来表示文本。在这篇文章中&#xff0c;我们将…

chatgpt赋能python:Python扫描在SEO中的重要性

Python扫描在SEO中的重要性 Python扫描是一种快速检测网站漏洞和异常的方式&#xff0c;也是SEO方案中不可或缺的一部分。一般来说&#xff0c;Python扫描被用来检测在网站上常见的安全风险&#xff0c;并且使用这种方式可以快速且准确地查找和修复问题。 什么是Python扫描 …

fftw的使用

1、下载编译 官网&#xff1a;http://www.fftw.org/index.html 2、FFT基础知识 2.1 概念 FFT分辨率可以表示为&#xff1a;fs/Nfft 频率分辨率的物理量就是&#xff1a;观测信号的时间窗长度&#xff0c; 时间窗越长&#xff08;N大&#xff09;&#xff0c; 对应频率分辨率…

chatgpt赋能python:Python循环与内存管理

Python循环与内存管理 在编写Python代码时&#xff0c;循环是不可避免的。但是循环&#xff0c;特别是无限循环&#xff0c;会导致内存问题&#xff0c;影响程序性能及其稳定性。本文将重点介绍Python循环和内存管理。 Python循环 在Python中&#xff0c;有三种循环结构&…

史上最全Android性能优化方案解析

Android中的性能优分为以下几个方面&#xff1a; 布局优化 网络优化 安装包优化 内存优化 卡顿优化 启动优化 …… 一.布局优化 布局优化的本质就是减少View的层级。常见的布局优化方案如下&#xff1a; 在LinearLayout和RelativeLayout都可以完成布局的情况下优先选择LinearL…

chatgpt赋能python:Python如何清理输出的屏幕?

Python 如何清理输出的屏幕&#xff1f; 在 Python 编程中&#xff0c;我们经常需要在控制台上输出一些信息。但是当输出信息过多时&#xff0c;控制台的屏幕可能会变得很杂乱。这时候&#xff0c;我们就需要清理掉原有的输出内容&#xff0c;以便更好地展示新的信息。那么&am…

26 VueComponent 其他属性的更新

前言 这是最近的碰到的那个 和响应式相关的问题 特定的操作之后响应式对象不“响应“了 引起的一系列的文章 主要记录的是 vue 的相关实现机制 呵呵 理解本文需要 vue 的使用基础, js 的使用基础 测试用例 比如这里看一下 class 的更新 测试用例如下, 增加 topClazz …

使用stable diffusion webui时,安装gfpgan失败的解决方案(windows下的操作)

1.问题描述 初次打开stable diffusion webui时&#xff0c;需要安装gfpgan等github项目。但在安装gfpgan时&#xff0c;显示RuntimeError: Couldnt install gfpgan 2.解决方案 无法安装gfpgan的原因是网络问题&#xff0c;就算已经科学上网&#xff0c;并设置为全局&#x…

imPlot的使用

1、概述 https://github.com/epezent/implot https://github.com/ocornut/imgui

【PWN · ret2libc】[NISACTF 2022]ezstack

一道简单的ret2libc——对标wiki的ret2libc1 目录 前言 一、题目信息 1.查看保护 2.IDA反汇编 3.pwntools获取表信息 & "/bin/sh"信息 二、exp 总结 前言 通过查看ELF文件信息&#xff0c;确定攻击方法&#xff0c;实现ret2libc1类型的攻击 一、题目…

强连通分量(SCC, Strongly Connected Components)

强连通分量&#xff08;SCC, Strongly Connected Component&#xff09; 强连通分量的概念强连通分量的应用强连通分量的算法——Tarjan算法 强连通分量的概念 在有向图中&#xff0c;任意两个顶点 v i v_i vi​ 和 v j v_j vj​ 互相可达&#xff08;也即存在路径 v i → v…

chatgpt赋能python:Python如何连接数据库?

Python如何连接数据库&#xff1f; Python作为一种高级编程语言&#xff0c;已经被广泛应用于数据科学和Web开发。连接数据库是Python的一项重要功能&#xff0c;可以使我们的代码访问各种数据源来收集、分析和存储数据。在这篇文章中&#xff0c;我们将介绍Python如何连接各种…

chatgpt赋能python:Python循环等待用户输入:提高交互性和可靠性

Python 循环等待用户输入&#xff1a;提高交互性和可靠性 作为一种高级编程语言&#xff0c;Python 可以通过很多方式实现与用户进行交互&#xff0c;其中最基础的方式是等待用户输入。在开发基于文本界面的应用程序、命令行工具或脚本时&#xff0c;这种输入等待机制可以提高…

JDK8 新特性 Stream API 进阶 (结合案例详解--通透--讲清)

&#x1f473;我亲爱的各位大佬们好&#x1f618;&#x1f618;&#x1f618; ♨️本篇文章记录的为 JDK8 新特性 Stream API 进阶 相关内容&#xff0c;适合在学Java的小白,帮助新手快速上手,也适合复习中&#xff0c;面试中的大佬&#x1f649;&#x1f649;&#x1f649;。 …

ruoyi-vue版本(十八)创建自己的项目,使用若依里面的技术,多数据源的实现

目录 1 创建自己的项目2 连接MySQL数据库(多数据源)2.1 若依实现多数据源2.1.1 主要思想2.2 第三方的依赖的实现1 创建自己的项目 1 创建一个空文件夹 2 idea 里面创建项目

GPU云服务器Stable Diffusion搭建保姆级教程

搭建Stable Diffusion最大门槛就是GPU。许多人的电脑配置太低&#xff0c;根本无法搭建。或者即使搭建出来&#xff0c;但是跑图太慢。说多了不通过&#xff0c;看下图。 选择服务器 我选择的是境外GPU服务器&#xff0c;windows版本&#xff08;73.59元&#xff09;。linux会…

SQL进阶教程读后总结与感想

1. 基本信息 SQL进阶教程 [日]MICK 人民邮电出版社,2017年11月出版&#xff0c;1版 1.1. 读薄率 书籍总字数455千字&#xff0c;笔记总字数25820字。 读薄率25820455000≈5.67% 1.2. 读厚方向 SQL权威指南&#xff08;第4版&#xff09; SQL解惑&#xff08;第2版&…

数据库数据量大了怎么办? 当然是分库分表,Sharding-JDBC了解一下?

Sharding-JDBC是一款基于JDBC规范的分布式数据库中间件&#xff0c;可以帮助Java应用轻松实现水平分库分表、读写分离等分布式数据库功能&#xff0c;并提供了方便易用、高可用、高性能的数据访问解决方案。本文将从以下几个方面进行详细介绍&#xff1a; Sharding-JDBC的原理…

chatgpt赋能python:Python录屏录音介绍

Python录屏录音介绍 在日常工作和学习中&#xff0c;录制屏幕和录制音频是一件很常见的事情。Python语言拥有强大的生态系统和第三方库支持&#xff0c;也可以轻松实现录制屏幕和录制音频的功能。本篇文章将介绍如何使用Python语言实现录屏录音功能。 Python录屏 录制屏幕可…

numpy包中的取余函数和取模函数numpy.remainder()numpy.mod()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 numpy包中的取余函数和取模函数 numpy.remainder() numpy.mod() 下列代码中np.remainder(m,2)输出的结果是&#xff1f; import numpy as np m np.array([4, 5, 6]) print("【显示】m &…