学习Pytest + Hypothesis——能帮你发现你自己都没想到的 bug

一、🧠 原理概述

Hypothesis 的核心由两部分组成:

1. 策略(strategies)定义"什么样"的数据

你用 hypothesis.strategies 定义数据类型,比如:

java 复制代码
@given(st.integers())

这表示 "任意整数"。

你可以定制规则,比如:

ini 复制代码
st.integers(min_value=0, max_value=1000)
st.lists(st.text(), min_size=1, max_size=5)
st.dictionaries(st.text(), st.integers())

这些叫做 策略对象(strategy),它描述了数据的"分布空间"。


2. 生成器 + 假设驱动搜索 + Shrinking 缩减失败案例

Hypothesis 不是瞎生成数据,而是采用类似搜索和优化的思路:

✅ 自动生成数据 + 路径覆盖
  • 它尝试生成多种数据组合:小的、大的、负数、空值、重复项、特殊字符、边界条件等
  • 会特别尝试边界值、极端情况、稀有值
❌ 发现失败 → 自动"缩减"成最小反例
  • 一旦测试失败,Hypothesis 会尝试找出 最简单能重现错误的输入(称为 shrinking)

举例:

python 复制代码
@given(st.lists(st.integers()))
def test_sum_non_negative(xs):
    assert sum(xs) >= 0

错误的假设:和永远非负

Hypothesis 可能生成 [1, 2, -100] 导致失败,但它最终会缩减[-1][-2],报告最小反例,便于你 debug。


📦 数据生成机制举个例子

st.text() 为例,它内部其实做了:

markdown 复制代码
1. 生成字符串长度(可能是0、1、2、1000等)
2. 生成字符(可能是ASCII、emoji、控制字符、换行等)
3. 随机拼接形成字符串

同样,st.floats() 会生成:

  • 正数、负数、0.0、-0.0
  • 无穷大 inf-inf
  • NaN
  • 边界值,如 1e-308, 1e308

你甚至可以明确要求排除某些值:

ini 复制代码
st.floats(allow_nan=False, allow_infinity=False)

二、🧪 入门组合:pytest + Hypothesis

我们从基础到进阶带你入门:


✅ 1. 安装

复制代码
pip install pytest hypothesis

✅ 2. 用 pytest 写基本测试

python 复制代码
# test_math.py
def add(x, y):
    return x + y

def test_add():
    assert add(1, 2) == 3

运行测试:

复制代码
pytest

✅ 3. 引入 Hypothesis 做"自动化输入测试"

python 复制代码
from hypothesis import given
import hypothesis.strategies as st

def add(x, y):
    return x + y

@given(st.integers(), st.integers())
def test_add_commutative(x, y):
    assert add(x, y) == add(y, x)
🧠 解读:
  • @given(st.integers(), st.integers()) 会自动生成很多组整数 (x, y)
  • 然后 pytest 会反复运行 test_add_commutative(x, y) 来测试这个性质是否成立
  • 这是"属性测试":不是测试特定输入,而是测试一个通用规律/属性

✅ 4. 再举一个进阶例子:字符串逆转

python 复制代码
@given(st.text())
def test_reverse_twice(s):
    assert s == s[::-1][::-1]

解释: 任何字符串 s,反转两次应该和原来一样。

Hypothesis 会生成各种字符串(包括空的、emoji、换行、乱码等),帮你找 bug!


✅ 5. 缩减失败输入(最强大功能之一)

比如你写了这个错误的函数:

python 复制代码
def is_palindrome(s):
    return s == s[::-1] and len(s) > 1

@given(st.text())
def test_palindrome_reverse(s):
    assert is_palindrome(s) == (s == s[::-1])

一旦出错,Hypothesis 会自动缩减出最简单的反例 (比如 ''),帮你快速定位 bug。


✅ 6. 常用策略(strategies)示例

类型 示例
整数 st.integers(min_value=0, max_value=100)
浮点 st.floats(allow_nan=False)
字符串 st.text()
列表 st.lists(st.integers())
字典 st.dictionaries(st.text(), st.integers())
布尔值 st.booleans()

你也可以组合它们构造复杂的数据结构。


📦 推荐项目结构

复制代码
my_project/
├── my_module.py
├── test_my_module.py   ← 用 pytest + Hypothesis 写测试

用命令运行所有测试:

复制代码
pytest

🚀 入门小任务建议

你可以试着写几个函数,并用 pytest + Hypothesis 验证它们:

  1. is_even(n):是否是偶数
  2. reverse(s):反转字符串
  3. sort_list(lst):排序后是否不减少元素
  4. divide(x, y):注意 y=0 的情况

练习答案如果可以大家可以分享在评论区

GitHub:github.com/HypothesisW...

相关推荐
m0_73812072几秒前
网络安全编程——Python编写基于UDP的主机发现工具(解码IP header)
python·网络协议·tcp/ip·安全·web安全·udp
北冥有羽Victoria5 分钟前
OpenCLI 操作网页 从0到1完整实操指南
vscode·爬虫·python·github·api·ai编程·opencli
handsomestWei7 分钟前
scikit-learn数据预处理模块
python·机器学习·scikit-learn
w_t_y_y11 分钟前
机器学习常用的python包(二)工具箱scikit-learn
python·机器学习·scikit-learn
用户83562907805121 分钟前
Python 自动拆分 Word 文档教程:按分节符与分页符处理
后端·python
陈天伟教授24 分钟前
心电心音同步分析-案例:原型设计一
开发语言·人工智能·python·语言模型·架构
我的xiaodoujiao24 分钟前
API 接口自动化测试详细图文教程学习系列9--Requests模块
python·学习·测试工具·pytest
jaycyj26 分钟前
Web端抓包工具操作与应用
测试
Allen_LVyingbo26 分钟前
量子计算Dirac Notation基本教学—从零基础到读懂量子信息论文(下)
开发语言·人工智能·python·数学建模·量子计算
Dxy12393102161 小时前
Python路径算法简介
开发语言·python·算法