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

如何在pytest中跳过测试但仍按原顺序执行session fixtures?

Selenium测试套件fixture执行顺序控制方案

问题背景与需求

我维护一个大型Selenium测试套件,用session级fixture在被测Web应用中创建测试数据(比如地点、人员、状态这类用户聚合数据)。所有依赖这类数据的测试都会关联对应fixture,每个fixture负责在应用中操作生成数据(套件默认每次运行前数据库已清空)。

这种设计能让我们运行任意测试子集,不会有数据依赖问题。简单测试模块示例:

test_a(fixture_a)
test_b(fixture_b)
test_c(fixture_a)

测试套件按指定模块顺序执行:

module_1
module_2
module_3

套件支持通过标签从指定模块开始顺序运行(比如从module_2开始,跳过module_1,后续正常执行)。

核心问题:
跳过测试时,fixture的执行顺序会被打乱,甚至可能不执行。比如跳过test_a后,fixture_a要等到test_c执行时才会运行。我需要实现:跳过指定测试,但仍让对应的fixture按原有顺序执行。

可行解决方案

1. 显式指定fixture执行顺序

利用pytest-order插件(需提前安装:pip install pytest-order)给fixture标记执行顺序,强制fixture按设定顺序运行,不受测试调用时机影响。

示例代码:

import pytest

@pytest.mark.order(1)
@pytest.fixture(scope="session")
def fixture_a():
    # 生成地点数据的逻辑
    return "地点数据"

@pytest.mark.order(2)
@pytest.fixture(scope="session")
def fixture_b():
    # 生成人员数据的逻辑
    return "人员数据"

如果fixture之间有逻辑依赖,也可以通过fixture嵌套调用固定顺序,比如让fixture_b依赖fixture_a,确保fixture_a先执行。

2. 添加预执行空测试

在模块中添加仅用于触发fixture的空测试,给这类测试单独标记。当需要跳过业务测试但保留fixture执行时,只跳过业务测试,保留预执行测试。

示例代码:

import pytest

# 预执行测试:仅触发对应fixture,无业务逻辑
@pytest.mark.pre_run
def test_trigger_fixture_a(fixture_a):
    pass

@pytest.mark.pre_run
def test_trigger_fixture_b(fixture_b):
    pass

# 业务测试
@pytest.mark.business
def test_a(fixture_a):
    # 业务测试逻辑
    pass

@pytest.mark.business
def test_b(fixture_b):
    # 业务测试逻辑
    pass

@pytest.mark.business
def test_c(fixture_a):
    # 业务测试逻辑
    pass

运行时跳过test_a但保留fixture执行的命令:

pytest -m "pre_run or (business and not test_a)"

3. 自定义pytest钩子自动触发fixture

通过pytest_collection_modifyitems钩子,在测试收集阶段自动插入虚拟测试来触发指定fixture,确保fixture按顺序执行。

示例钩子实现(放在conftest.py中):

def pytest_collection_modifyitems(config, items):
    # 定义需要提前执行的fixture列表,按顺序排列
    required_fixtures = ["fixture_a", "fixture_b"]
    
    from _pytest.python import Function
    import types

    for fixture_name in required_fixtures:
        # 创建虚拟测试函数,仅获取fixture
        def dummy_test(request):
            request.getfixturevalue(fixture_name)
        
        # 包装成pytest可识别的测试项
        dummy_func = types.FunctionType(dummy_test.__code__, globals(), f"test_trigger_{fixture_name}")
        dummy_item = Function.from_parent(config.rootpath, func=dummy_func)
        # 将虚拟测试插入到测试列表的最前面
        items.insert(0, dummy_item)

这样无论哪些测试被跳过,指定的fixture都会在测试开始前按顺序执行。

4. 抽离数据初始化脚本

把fixture中的数据生成逻辑单独抽成初始化脚本,运行测试前手动或通过脚本调用需要的初始化步骤,再执行测试。

示例初始化脚本(data_init.py):

def init_fixture_a():
    # 生成地点数据的Selenium操作逻辑
    print("初始化fixture_a数据")

def init_fixture_b():
    # 生成人员数据的Selenium操作逻辑
    print("初始化fixture_b数据")

if __name__ == "__main__":
    import sys
    if len(sys.argv) < 2:
        print("请指定要初始化的fixture,如:python data_init.py fixture_a")
        sys.exit(1)
    fixture_name = sys.argv[1]
    if fixture_name == "fixture_a":
        init_fixture_a()
    elif fixture_name == "fixture_b":
        init_fixture_b()

运行流程:

# 先初始化fixture_a数据
python data_init.py fixture_a
# 跳过test_a运行测试
pytest -k "not test_a"

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 09:25:56