Pytest 插件:pytest_runtest_protocol
Hook 方法之 pytest_runtest_protocol:
pytest_runtest_protocol :
官方给的解释是:为给定的测试项目执行runtest_setup / call / teardown协议;
可以在执行每个测试用例的各个阶段进行钩子拦截,比如在测试用例开始执行前、执行中间某一步骤、执行完成后等,从而可以方便地进行一些额外的操作或者扩展功能。
pytest 的默认 pytest_runtest_protocol
实现会按顺序执行以下操作:
- 调用
pytest_runtest_logstart
钩子,标记测试开始 - 调用
pytest_runtest_setup
钩子,执行测试前置条件 - 调用
pytest_runtest_call
钩子,执行测试函数本身 - 调用
pytest_runtest_teardown
钩子,执行测试后置清理 - 调用
pytest_runtest_logfinish
钩子,标记测试结束
The default runtest protocol is this (see individual hooks for full details):
-
pytest_runtest_logstart(nodeid, location)
-
Setup phase:
-
call = pytest_runtest_setup(item)
(wrapped inCallInfo(when="setup")
) -
report = pytest_runtest_makereport(item, call)
-
pytest_runtest_logreport(report)
-
pytest_exception_interact(call, report)
if an interactive exception occurred
-
-
Call phase, if the setup passed and the
setuponly
pytest option is not set:-
call = pytest_runtest_call(item)
(wrapped inCallInfo(when="call")
) -
report = pytest_runtest_makereport(item, call)
-
pytest_runtest_logreport(report)
-
pytest_exception_interact(call, report)
if an interactive exception occurred
-
-
Teardown phase:
-
call = pytest_runtest_teardown(item, nextitem)
(wrapped inCallInfo(when="teardown")
) -
report = pytest_runtest_makereport(item, call)
-
pytest_runtest_logreport(report)
-
pytest_exception_interact(call, report)
if an interactive exception occurred
-
-
pytest_runtest_logfinish(nodeid, location)
Parameters:
-
item (Item) – Test item for which the runtest protocol is performed.
-
nextitem (Item | None) – The scheduled-to-be-next test item (or None if this is the end my friend).
def pytest_runtest_protocol(item, nextitem):print("\n[pytest_generate_protocol]这个钩子函数在每个测试用例开始和结束时被调用",item.name)
def pytest_runtest_protocol(item, nextitem):# 自定义测试开始逻辑item.ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location)# 自定义测试执行流程item.ihook.pytest_runtest_setup(item=item)item.ihook.pytest_runtest_call(item=item)item.ihook.pytest_runtest_teardown(item=item, nextitem=nextitem)# 自定义测试结束逻辑item.ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location)return True
常见应用场景
- 性能监控:在协议中插入时间记录逻辑,统计每个测试用例的执行时长。
- 动态跳过测试:根据运行时条件(如环境变量)决定是否跳过某些测试。修改测试执行顺序或逻辑。
- 日志增强:在测试执行前后输出详细日志,便于调试。
- 在特定条件下跳过某些测试步骤 集成自定义报告生成机制。
- 实现特殊的测试环境管理。
注意事项
自定义实现时需要确保正确处理所有必要的钩子调用,返回 True 表示测试协议已处理,False 表示交由其他实现处理 避免在钩子中引入过多复杂逻辑,以免影响测试性能 确保正确处理异常情况,避免影响后续测试执行。
自定义实现示例
以下是一个自定义 pytest_runtest_protocol
的示例,通过重写钩子添加日志功能:
def pytest_runtest_protocol(item, nextitem):# 自定义前置操作print(f"Starting test: {item.name}")# 调用默认的测试协议(包括 setup/call/teardown)result = pytest_runtest_protocol.__wrapped__(item, nextitem) if hasattr(pytest_runtest_protocol, '__wrapped__') else None# 自定义后置操作print(f"Finished test: {item.name}")return result
注意事项
- 修改
pytest_runtest_protocol
需谨慎,避免破坏默认流程导致测试失败。 - 建议优先通过标准钩子(如
pytest_runtest_setup
)实现扩展,而非直接重写协议。 - 使用
pytest_runtest_logstart
和pytest_runtest_logfinish
等辅助钩子可以减少侵入性。
通过合理利用此协议,可以高度灵活地控制 pytest 的测试行为,满足复杂项目的需求。