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

相关推荐
Y幽谷客6 小时前
Python加载本地大模型(Qwen3.5 8B)
python·大模型
伞伞悦读6 小时前
【第36期】Python 目录与路径详解:pathlib、文件遍历、创建、复制、移动和删除风险
开发语言·python
线上放牧人6 小时前
Windows删除图标缓存
windows·python·pyqt
qq_5470261797 小时前
Python 变量和简单数据类型
python
智搜广告8 小时前
智搜广告:科技行业AI回答优化公司如何破局
大数据·python·elasticsearch·geo
IpdataCloud9 小时前
AI智能体调用工具怎么核验来源IP?归属地、网络类型与代理风险识别(含Python代码)
数据库·python·tcp/ip
2601_966949659 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
蒸鱼Yuzheng9 小时前
Python 游戏测试开发怎么准备:日志解析、接口校验、并发与可维护性
自动化测试·python·测试开发·面试题·游戏测试
Ivanqhz9 小时前
BM1688 双核架构
python·深度学习·神经网络·cnn·mlir
Java后端的Ai之路10 小时前
Python进阶探索17 - Python中的深拷贝与浅拷贝
人工智能·python·ai·浅拷贝·深拷贝