Pytest 使用nodeid运行测试用例

本文介绍了如何在API接口自动化平台中实现失败测试用例的批量重跑功能。通过收集pytest的失败case nodeid,处理包含中文参数的nodeid,并利用pytest的nodeid运行机制,可以实现按需重新运行失败的测试用例。

Pytest 使用nodeid运行测试用例

背景

近期在做API接口自动化平台,平台的主要功能是创建自动化任务、查看报告、查看运行失败用例及一些针对不同类型任务的搜索功能。
最近想增加一个失败用例重跑的功能。虽然pytest有针对失败重跑的插件(pytest-rerunfailures),但是插件是集成在pytest的每次任务运行过程中进行的。比如一共跑10个case,第1个case失败后,如果设置了“–reruns”参数,则紧接着就会重新跑这个失败的case。
而我设想的功能是在整个pytest任务执行结束后,再重新批量运行这些失败的cases。大概就是当前任务行,有一个[重跑]按钮,点击这个按钮就可以新建一个任务。

步骤
1. 收集失败case nodeid

想要完成这个目标,做的第一步工作就是收集每次运行失败的case,这个相对简单,使用pytest提供的hook函数即可实现。这里我使用了def pytest_runtest_logreport(report): 实现。
收集到的case nodeid类似这样:
xxx/tests/test_all/test_homepage.py::TestHomePageAPI::test_homepage_api[SA-1-10-200-A_AR]
关于nodeid的描述,pytest的官方文档给出了大概的解释:

Each collected test is assigned a unique nodeid which consist of the module filename followed by specifiers like class names, function names and parameters from parametriz

<think>好的,用户想了解如何使用pytest的钩子函数来获取测试用例中子测试用例的参数。首先,我需要回忆一下pytest中处理子测试用例的相关机制,尤其是使用@pytest.mark.parametrize的情况,以及子测试通常如何生成。 用户提到的钩子函数,可能需要用到pytest_collection_modifyitems或者pytest_generate_tests这样的钩子。不过,具体到子测试的参数获取,可能是在生成测试项的时候处理的。比如,当使用参数化时,每个参数组合会生成不同的测试用例,而子测试可能指的是这些参数化的用例。 接下来,我需要确定如何在这些测试用例被收集或生成时,获取它们的参数。pytest_generate_tests这个钩子函数是在生成测试用例时调用的,可以在这里修改metafunc对象,从而影响测试参数的生成。但用户的需求是获取已经生成的子测试的参数,所以可能需要另一个钩子,比如pytest_itemcollected,它在每个测试项被收集时触发。 不过,pytest中每个测试项的参数信息通常存储在item对象的fixtureinfo或者callspec属性中。例如,item.callspec.params可以获取到参数化的参数值。因此,可能需要编写一个钩子函数,在收集测试项时,遍历每个item,检查是否有callspec,然后提取参数。 另外,用户可能需要一个例子来具体说明如何实现这一点。比如,在conftest.py文件中定义pytest_collection_modifyitems钩子,遍历所有收集的测试项,并打印出它们的参数。 还需要注意,子测试可能指的是使用unittest中的subTest上下文管理器,但更常见的是参数化测试用例。这里假设用户指的是参数化生成的子测试用例。 总结步骤应该是:创建一个conftest.py文件,使用pytest_collection_modifyitems钩子,遍历items,检查每个item是否有callspec属性,如果有,则提取参数。然后打印或处理这些参数。 可能需要验证这个方法的正确性,比如写一个简单的参数化测试用例运行pytest时查看是否成功获取参数。同时,需要注意不同pytest版本中钩子的使用是否有差异,确保兼容性。 另外,用户可能需要知道如何访问这些参数,以便进行进一步处理,比如生成自定义报告或过滤测试用例。因此,在回答中应该提供具体的代码示例,并解释每个部分的作用,帮助用户理解和应用。 最后,确保回答结构清晰,分步骤说明,并提醒用户注意可能的陷阱,比如钩子函数的正确命名,conftest.py的位置等。</think>在pytest中,通过钩子函数获取子测试用例(即参数化生成的用例)参数,可以通过以下步骤实现: --- ### 一、核心原理 当使用`@pytest.mark.parametrize`生成参数化测试时,每个子测试用例的元数据会存储在`request`对象的`param`属性或测试项的`callspec.params`中。通过`pytest_collection_modifyitems`钩子可以拦截已收集的测试用例。 --- ### 二、实现步骤 #### 1. 创建`conftest.py`文件 在项目根目录或测试目录中创建该文件,这是pytest默认加载钩子的位置。 #### 2. 编写钩子函数 ```python def pytest_collection_modifyitems(items): for item in items: # 检查是否为参数化用例 if hasattr(item, "callspec"): params = item.callspec.params print(f"测试用例 {item.name} 的参数: {params}") ``` #### 3. 参数化测试示例 ```python import pytest @pytest.mark.parametrize("a,b,expected", [ (1, 2, 3), (4, 5, 9) ]) def test_add(a, b, expected): assert a + b == expected ``` --- ### 三、运行观察 执行测试时会输出: ``` 测试用例 test_add[1-2-3] 的参数: {'a': 1, 'b': 2, 'expected': 3} 测试用例 test_add[4-5-9] 的参数: {'a': 4, 'b': 5, 'expected': 9} ``` --- ### 四、关键属性解析 - `item.callspec.params`:返回参数字典 - `item.name`:显示包含参数值的完整用例名称 - `item.nodeid`:获取用例唯一路径标识(如`test_sample.py::test_add[1-2-3]`) --- ### 五、高级用法 如需动态修改参数,可使用`pytest_generate_tests`钩子: ```python def pytest_generate_tests(metafunc): if "input" in metafunc.fixturenames: metafunc.parametrize("input", [1, 2, 3]) ``` --- ### 六、注意事项 1. 确保钩子函数放在`conftest.py`中 2. 参数化嵌套时`callspec.params`会包含所有层级参数 3. 通过`item.config`可访问全局配置对象 通过这种方法可以轻松实现测试参数审计、动态过滤用例等高级操作。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值