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

相关推荐
烛阴7 小时前
简单入门Python装饰器
前端·python
好开心啊没烦恼8 小时前
Python 数据分析:numpy,说人话,说说数组维度。听故事学知识点怎么这么容易?
开发语言·人工智能·python·数据挖掘·数据分析·numpy
面朝大海,春不暖,花不开8 小时前
使用 Python 实现 ETL 流程:从文本文件提取到数据处理的全面指南
python·etl·原型模式
2301_805054569 小时前
Python训练营打卡Day59(2025.7.3)
开发语言·python
万千思绪9 小时前
【PyCharm 2025.1.2配置debug】
ide·python·pycharm
微风粼粼11 小时前
程序员在线接单
java·jvm·后端·python·eclipse·tomcat·dubbo
云天徽上11 小时前
【PaddleOCR】OCR表格识别数据集介绍,包含PubTabNet、好未来表格识别、WTW中文场景表格等数据,持续更新中......
python·ocr·文字识别·表格识别·paddleocr·pp-ocrv5
你怎么知道我是队长11 小时前
python-input内置函数
开发语言·python
叹一曲当时只道是寻常12 小时前
Python实现优雅的目录结构打印工具
python
ly15612 小时前
pytest-selenium的作用和常用操作-来自ai-个人留存
测试