正确调用benchmark fixture需显式声明为函数参数,如def test_sort_performance(benchmark): result = benchmark(sorted, [3, 1, 4, 1, 5]);漏参数或误用@pytest.mark.benchmark均会导致失败。

直接用 pytest-benchmark 跑性能测试,核心就一条:把待测函数写成普通 pytest 测试函数,再用 benchmark fixture 调用它——不是装饰器,也不是单独命令行参数。
如何正确调用 benchmark fixture
benchmark 是 pytest 自动注入的 fixture,必须作为函数参数显式声明。常见错误是漏掉这个参数,或试图用 @pytest.mark.benchmark 直接修饰函数(这不会触发基准测试)。
- ✅ 正确写法:
def test_sort_performance(benchmark): result = benchmark(sorted, [3, 1, 4, 1, 5]) - ❌ 错误写法:
def test_sort_performance(): ...(缺少benchmark参数,会报fixture 'benchmark' not found) - ❌ 错误写法:
@pytest.mark.benchmark def test_sort_performance(): ...(标记无效,不执行基准测试)
benchmark() 的三种常用调用方式及适用场景
传入函数+参数的方式不同,影响的是被测代码的执行粒度和结果解释性:
-
benchmark(func, *args, **kwargs):最常用,等价于func(*args, **kwargs),测量单次调用开销(适合纯函数、无状态操作) -
benchmark.pedantic(func, args=..., setup=..., iterations=..., rounds=...):控制更细,比如想固定跑 100 次迭代、重复 5 轮取中位数,或需要 setup 函数预热/构造数据 -
benchmark(lambda: func(...)):适合带闭包、需延迟求值或含副作用的逻辑(但注意 lambda 本身有微小开销,对 sub-microsecond 级别敏感时需留意)
为什么 test 运行后没看到性能报告?
pytest 默认不输出 benchmark 结果,必须显式启用输出格式或保存到文件:
- 加
--benchmark-only才只运行 benchmark 测试(否则普通 test 和 benchmark test 都会跑,但后者不输出) - 加
--benchmark-compare可对比历史结果(需先用--benchmark-save=xxx存档) - 最简验证方式:
pytest --benchmark-only -v,确保看到类似Median (50.0%): 12.45 us的行 - 注意:如果测试函数里没调用
benchmark(...),pytest 会静默跳过该 benchmark 测试,也不会报错
setup 和 teardown 容易被忽略的细节
很多性能差异其实来自数据构造或环境初始化,但 benchmark 默认不包含 setup 时间。要用 pedantic 模式显式分离:
-
setup函数返回一个元组(args, kwargs)或可调用对象,用于每次迭代前准备输入 -
setup本身不计入耗时,但返回的数据会被传给目标函数——这意味着如果你在setup里做了 heavy 初始化,又没把它移到setup外,结果会失真 - 没有内置 teardown,如需清理(比如临时文件、缓存),得在
setup返回的 callable 里手动处理,或改用普通 pytest fixture +yield配合benchmark
真正卡住人的往往不是语法,而是没意识到 benchmark 测的是“函数调用”而非“函数定义”,以及默认不包含 setup 开销——这两点一旦搞反,测出来的数字就完全不可比。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











