学习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...

相关推荐
沈浩(种子思维作者)1 小时前
真的能精准医疗吗?癌症能提前发现吗?
人工智能·python·网络安全·健康医疗·量子计算
njsgcs2 小时前
ue python二次开发启动教程+ 导入fbx到指定文件夹
开发语言·python·unreal engine·ue
io_T_T2 小时前
迭代器 iteration、iter 与 多线程 concurrent 交叉实践(详细)
python
华研前沿标杆游学2 小时前
2026年走进洛阳格力工厂参观游学
python
Carl_奕然2 小时前
【数据挖掘】数据挖掘必会技能之:A/B测试
人工智能·python·数据挖掘·数据分析
AI小怪兽2 小时前
基于YOLOv13的汽车零件分割系统(Python源码+数据集+Pyside6界面)
开发语言·python·yolo·无人机
wszy18093 小时前
新文章标签:让用户一眼发现最新内容
java·python·harmonyos
Eric.Lee20213 小时前
python实现 mp4转gif文件
开发语言·python·手势识别·手势交互·手势建模·xr混合现实
EntyIU3 小时前
python开发中虚拟环境配置
开发语言·python
wszy18093 小时前
顶部标题栏的设计与实现:让用户知道自己在哪
java·python·react native·harmonyos