pytest_runtest_makereport 是 pytest 的 hook 函数,在每个测试项执行完毕后、生成报告前触发,用于获取测试结果、异常及堆栈等原始数据,支持向 report 添加自定义字段或记录日志。

pytest_runtest_makereport 是什么,它在哪个阶段触发?
pytest_runtest_makereport 是 pytest 提供的 hook 函数,用于在每个测试项(test item)执行完后、生成测试报告前被调用。它不负责执行测试,也不控制测试流程,只提供一个“观察+干预”的机会——你可以拿到当前测试的执行结果(pass/fail/skip)、异常信息、堆栈、耗时等原始数据。
注意:它不是在测试函数内部运行的,而是在 pytest 的内部调度循环中调用,因此不能直接修改测试逻辑,但可以往 report 对象里塞自定义字段,或触发日志写入。
如何在 conftest.py 中正确注册并获取失败详情?
必须把 pytest_runtest_makereport 放在项目根目录或测试目录下的 conftest.py 文件中(不能放在 test_*.py 里),且函数签名要严格匹配:
def pytest_runtest_makereport(item, call):
if call.when == "call" and call.excinfo is not None:
# 这里是测试主体执行失败时(非 setup/teardown)
print(f"[FAIL] {item.name}: {call.excinfo.exconly()}")
关键点:
立即学习“Python免费学习笔记(深入)”;
-
call.when == "call"才代表测试函数本身执行完毕;"setup"和"teardown"阶段也可能失败,但通常不归为用例失败 -
call.excinfo仅在出错时非空,类型是ExceptionInfo,可用.exconly()获取单行错误摘要,.reprcrash.message拿具体报错消息 - 不要在 hook 里 raise 异常,否则会中断 pytest 报告生成流程
怎么把失败用例的完整 traceback 写进本地日志文件?
pytest 默认不把 traceback 输出到文件,pytest_runtest_makereport 是最轻量可控的切入点。推荐做法是用 Python 标准 logging 模块追加写入,避免多进程冲突:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s [%(levelname)s] %(message)s",
handlers=[logging.FileHandler("test_failures.log", encoding="utf-8")]
)
<p>def pytest_runtest_makereport(item, call):
if call.when == "call" and call.excinfo is not None:
logger = logging.getLogger(<strong>name</strong>)
logger.error(
f"Test failed: {item.nodeid}\n"
f"Error: {call.excinfo.exconly()}\n"
f"Traceback:\n{call.excinfo.getrepr(showlocals=False)}"
)</p>注意事项:
-
call.excinfo.getrepr()返回的是 pytest 格式化的 traceback 对象,需调用str(...)或.tostring()才能转成字符串;上面示例用了getrepr(showlocals=False)避免日志过大 - 别用
print()替代 logging——它不会落盘,且和 pytest 的 -s 参数行为耦合 - 如果用
pytest-xdist并行运行,多个 worker 可能同时写同一文件,建议按 worker ID 分日志名,或改用线程安全的 handler
为什么加了 hook 却没看到日志?常见排查点
hook 不生效往往不是代码写错了,而是环境或加载路径问题:
-
conftest.py必须在 pytest 启动时能 import 到——运行pytest --traceconfig看是否列出了你的 conftest - 函数名拼错,比如写成
pytest_runtest_make_report(少个 r)或大小写不对 - 在
pytest_configure里动态 patch 了 hook,但未正确注册;应优先用标准 conftest 方式 - pytest 版本太老(excinfo 属性,建议用
pytest>=7.0
定制日志真正难的不是写 hook,而是区分哪些失败需要记录、要不要截断 traceback、是否要关联 fixture 状态——这些都得靠 item 和 call 两个参数组合判断,不能只看 excinfo 有无。

















