在 pytest 测试项目中,我遇到过这样的场景 内外层同时写environment.properties,内层hook的将会被覆盖掉
project/
├── conftest.py # 外层 hook
└── module/
└── conftest.py # 内层 hook当外层定义了 pytest_sessionfinish 时,它会完全覆盖内层的同名 hook。这会导致:
# module/conftest.py
import pytest
@pytest.hookimpl(hookwrapper=True)
def pytest_sessionfinish(session, exitstatus):
# 执行外层和其他插件的 sessionfinish
yield
# 追加自定义行为(安全区域)
# your_code# module/conftest.py
import os
import pytest
from pathlib import Path
def merge_properties(base: dict, new: dict) -> dict:
"""智能合并属性字典"""
merged = base.copy()
for k, v in new.items():
# 处理数组型属性(如 tags)
if k in merged andisinstance(merged[k], list):
ifisinstance(v, list):
merged[k] = merged[k] + v
else:
merged[k] = merged[k] + [v]
else:
merged[k] = v
return merged
@pytest.hookimpl(hookwrapper=True)
def pytest_sessionfinish(session, exitstatus):
yield # 等待其他 hook 完成
report_dir = session.config.option.allure_report_dir
if not report_dir:
return
prop_file = Path(report_dir) / "environment.properties"
# 读取现有属性
existing_props = {}
if prop_file.exists():
with open(prop_file, "r") as f:
for line in f:
if"="in line:
key, value = line.strip().split("=", 1)
existing_props[key] = value
# 定义要追加/修改的属性
new_props = {
"MODULE_LEVEL": "inner_module",
"EXTRA_TAGS": ["stability", "performance"],
"CONFTEST_VERSION": os.getenv("CONFTEST_VERSION", "1.0.0")
}
# 智能合并
merged_props = merge_properties(existing_props, new_props)
# 重写文件
withopen(prop_file, "w") as f:
for key, value in merged_props.items():
ifisinstance(value, list):
# 处理数组属性
for item in value:
f.write(f"{key}={item}\n")
else:
f.write(f"{key}={value}\n")简单画了个原理图

执行顺序保障:
1. 错误隔离:
try:
yield
finally:
# 即使外层hook崩溃也会执行
log_cleanup_actions()2. 上下文访问:
@pytest.hookimpl(hookwrapper=True)
def pytest_sessionfinish(session, exitstatus):
# 获取yield前的结果
result = yield
# 检查外层hook的执行结果
if result.excinfo:
send_alert("外层hook执行失败")Hook 类型 | 适用场景 | |
|---|---|---|
hookwrapper | 包裹其他hook实现 | |
tryfirst/trylast | 控制执行顺序 | |
optionalhook | 可选实现 | |
historic | 跨会话事件 |
通过本文介绍的技术可以在不破坏现有测试框架的前提下,安全地扩展 pytest 的会话终结行为
参考文档:
https://docs.pytest.org/en/stable/
#Pytest #PytestHook