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

相关推荐
程序员的世界你不懂3 小时前
Appium+python自动化(八)- 认识Appium- 下章
python·appium·自动化
恸流失3 小时前
DJango项目
后端·python·django
Julyyyyyyyyyyy4 小时前
【软件测试】web自动化:Pycharm+Selenium+Firefox(一)
python·selenium·pycharm·自动化
蓝婷儿5 小时前
6个月Python学习计划 Day 15 - 函数式编程、高阶函数、生成器/迭代器
开发语言·python·学习
love530love5 小时前
【笔记】在 MSYS2(MINGW64)中正确安装 Rust
运维·开发语言·人工智能·windows·笔记·python·rust
水银嘻嘻6 小时前
05 APP 自动化- Appium 单点触控& 多点触控
python·appium·自动化
狐凄6 小时前
Python实例题:Python计算二元二次方程组
开发语言·python
烛阴7 小时前
Python枚举类Enum超详细入门与进阶全攻略
前端·python
Mikhail_G8 小时前
Python应用函数调用(二)
大数据·运维·开发语言·python·数据分析
weixin_472339469 小时前
使用Python提取PDF元数据的完整指南
java·python·pdf