You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使pytest.main重复执行test_init与test_deinit测试用例?

pytest重复执行初始化/清理用例被跳过的解决思路

问题背景

我需要按如下方式调用pytest执行测试:

tests = [
    'path\\testfile.py::test_init',
    'path\\testfile.py::test1',
    'path\\testfile.py::test2',
    'path\\testfile.py::test_deinit',
    'path\\testfile.py::test_init',
    'path\\testfile.py::test3',
    'path\\testfile.py::test4',
    'path\\testfile.py::test_deinit'
]

pytest.main(tests)

但pytest会跳过列表中重复的test_init和test_deinit,实际只执行6个用例,导致test3、test4没有对应的初始化与硬件清理操作。每组测试(test1/test2、test3/test4)必须单独执行test_init前置初始化和test_deinit后置清理,需要让8个用例完全按列表顺序执行。

现有测试结构

testfile.py中的测试套件定义如下:

child1 = {
    'name':'child1_suite_name',
    'tests':[test1, test2]
}

child2 = {
    'name':'child2_suite_name',
    'tests':[test3, test4]
}

testsuite = {
    'name': 'test suite',
    'setup': test_init, 
    'teardown': test_deinit, 
    'tests' :[child1, child2]
}

现有框架可解析该字典并调用对应测试、setup与teardown,但我需要通过pytest来执行。

已尝试的无效方案

  • 使用fixture:需要在测试用例参数中显式引入,不符合当前调用方式的需求
  • 使用setup_module:仅在文件所有测试前后执行一次,无法实现每组测试单独初始化/清理

解决思路

思路1:动态生成唯一命名的初始化/清理用例

pytest跳过重复用例是因为识别到同一个函数引用,因此可以给每组测试的初始化/清理生成唯一命名的函数副本:

# testfile.py
def test_init():
    # 原初始化逻辑(硬件控制相关)
    pass

def test_deinit():
    # 原清理逻辑(硬件控制相关)
    pass

# 为每组测试生成唯一命名的初始化/清理用例
test_init_group1 = test_init
test_deinit_group1 = test_deinit
test_init_group2 = test_init
test_deinit_group2 = test_deinit

# 原测试用例test1、test2、test3、test4保持不变

修改调用列表为:

tests = [
    'path\\testfile.py::test_init_group1',
    'path\\testfile.py::test1',
    'path\\testfile.py::test2',
    'path\\testfile.py::test_deinit_group1',
    'path\\testfile.py::test_init_group2',
    'path\\testfile.py::test3',
    'path\\testfile.py::test4',
    'path\\testfile.py::test_deinit_group2'
]
pytest.main(tests)

这样每个初始化/清理用例都有唯一标识,pytest会按顺序执行全部8个用例。

思路2:利用pytest钩子自定义测试集合与执行顺序

编写conftest.py,通过pytest_collection_modifyitems钩子重新组织测试用例的执行顺序,强制每组测试绑定对应的初始化/清理:

# conftest.py
def pytest_collection_modifyitems(items):
    # 定义两组测试的执行序列
    test_groups = [
        ['test_init', 'test1', 'test2', 'test_deinit'],
        ['test_init', 'test3', 'test4', 'test_deinit']
    ]
    reordered_items = []
    for group in test_groups:
        for case_name in group:
            # 找到对应测试项并加入新列表,移除原列表中的项避免重复
            for item in items[:]:
                if item.name == case_name:
                    reordered_items.append(item)
                    items.remove(item)
    # 替换原测试集合为重新排序后的集合
    items[:] = reordered_items

注意:此方法需要确保pytest不对重复用例去重,若仍有跳过问题,可以通过复制测试项实例的方式解决(比如使用copy.deepcopy(item))。

思路3:直接复用现有框架的套件执行逻辑

现有框架已经支持解析测试套件字典并为每个子套件执行setup/teardown,无需转成pytest用例列表,直接调用框架的执行入口即可:

# 假设现有框架提供run_suite方法执行测试套件
from your_framework import run_suite

run_suite(testsuite)

这种方式完全符合每组测试单独初始化/清理的需求,无需依赖pytest的用例执行逻辑。

内容的提问来源于stack exchange,提问作者Seafood

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 20:47:42