pytest测试执行结束时如何获取用例test_case_id对接Testrail
pytest集成TestRail用例ID映射实现方案
核心问题说明
你当前写法中test_case_id是测试函数内部的局部变量,pytest默认无法直接在钩子中读取,且原有代码未初始化session级别的结果存储属性,运行时会抛出属性不存在的错误。以下实现完全兼容你现有用例写法,最终可直接输出{test_case_id: 结果}格式的映射字典。
完整实现代码(兼容现有函数内定义ID的写法)
直接替换conftest.py中对应内容即可:
import pytest import logging logger = logging.getLogger(__name__) def pytest_configure(session): # 初始化会话级存储结构,解决属性不存在的报错 session.results = {} session.testrail_case_result = {} # 存储最终需要的<用例ID:执行结果>映射 @pytest.hookimpl(tryfirst=True, hookwrapper=True) def pytest_runtest_makereport(item, call): outcome = yield result = outcome.get_result() # 仅处理用例核心执行阶段的结果,跳过setup、teardown阶段的干扰 if result.when == 'call': test_case_id = None # 从测试函数执行帧读取局部变量中的test_case_id,兼容固定值、动态生成值的场景 try: target_frame = call.excinfo.traceback[-1].frame if call.excinfo else result._traceback[-1].frame test_case_id = target_frame.f_locals.get('test_case_id') except Exception as e: logger.warning(f"用例{item.name}未读取到test_case_id定义: {str(e)}") # 组装结果:可按需选择布尔值/字符串格式 # 布尔值格式:True=通过 False=失败 case_result = result.passed # 字符串格式替换为下一行即可 # case_result = "Passed" if result.passed else "Failed" if test_case_id is not None: item.session.testrail_case_result[test_case_id] = case_result # 保留原有结果存储逻辑 item.session.results[item] = result def pytest_sessionfinish(session): # 保留原有测试统计逻辑 passed_amount = sum(1 for res in session.results.values() if res.passed) failed_amount = sum(1 for res in session.results.values() if res.failed) logger.info('**** Test Summary ****') logger.info(f'Passed Test Cases Count -> {passed_amount}') logger.info(f'Failed Test Cases Count -> {failed_amount}') # 此处即可拿到最终映射字典,直接用于TestRail结果上报 logger.info(f'TestRail用例执行结果映射: {session.testrail_case_result}') # 输出示例:{10: True, 20: False} 或 {10: 'Passed', 20: 'Failed'}
更稳定的推荐写法(自定义Marker标记用例ID)
在函数内部定义局部变量的方式存在兼容风险:如果用例在执行到test_case_id=xx赋值行之前就抛出异常,会无法读取到ID。更推荐使用pytest原生marker能力标记用例ID,稳定性更高,不受用例执行异常影响。
- 注册自定义marker,在
pytest_configure中添加如下代码:
def pytest_configure(config): # 注册用例ID标记 config.addinivalue_line( "markers", "test_case_id(id): 标记TestRail平台对应测试用例ID" ) # 原有初始化逻辑保留 config.session.results = {} config.session.testrail_case_result = {}
- 修改测试用例写法,用marker传入ID:
import pytest @pytest.mark.test_case_id(10) def test_login1(): # 原有测试逻辑 assert True @pytest.mark.test_case_id(20) def test_login2(): # 原有测试逻辑 assert False
- 替换ID读取逻辑,无需再读执行帧局部变量,直接从marker取值即可:
# 替换pytest_runtest_makereport中读取test_case_id的try-except块 id_marker = item.get_closest_marker('test_case_id') test_case_id = id_marker.args[0] if id_marker else None
注意事项
- 如果需要上报setup/teardown阶段的用例失败结果,可以调整
result.when的判断逻辑,把对应阶段的结果也纳入映射。 - 最终的
session.testrail_case_result字典可直接在pytest_sessionfinish钩子中遍历,调用TestRail接口完成结果批量上报。
内容的提问来源于stack exchange,提问作者Megha Dalvi
相关产品推荐
相关产品推荐

