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

pytest parametrize参数生成函数多次调用的问题及解决

问题原因

在@pytest.mark.parametrize的参数中,_get_test_run_configs()[0]和_get_test_run_configs()[1]是两个独立的函数调用——pytest在解析装饰器阶段会分别执行这两个调用,甚至在测试收集过程中可能重复执行装饰器相关逻辑,导致_get_test_run_configs被多次触发。每次调用都会生成新的start_time,加上_generate_test_case_names里会修改run.name(每次调用追加新时间戳),最终导致测试用例名称的时间戳各不相同。

修复方案

核心思路是确保_get_test_run_configs只被调用一次,把结果缓存下来再传给parametrize。这里推荐两种简单有效的方式:

方式一:提前计算结果并复用

在模块级别提前调用函数,把结果存为变量,再将变量传入装饰器:

import time
import pytest

def _get_test_run_configs():
    start_time = time.time()

    # 替换成你的实际逻辑,生成测试参数列表
    test_runs_list = [("design1", type('Run', (), {'name': 'run1'})(), "hash1"),
                      ("design2", type('Run', (), {'name': 'run2'})(), "hash2")]

    test_case_names = _generate_test_case_names(test_runs_list, str(start_time))
    return test_runs_list, test_case_names


def _generate_test_case_names(runs_list: list, start_time: str) -> list:
    test_case_names = []
    for design, run, run_hash in runs_list:
        run.name = f"{run.name}_{start_time}"
        test_case_names.append(run.name)
    return test_case_names

# 提前调用一次,保存结果
test_runs_configs, test_case_ids = _get_test_run_configs()

@pytest.mark.parametrize(
    "design, run, run_hash", test_runs_configs, ids=test_case_ids
)
def test_run_game_day(design, run, run_hash):
    assert True

这样模块加载时就会执行一次_get_test_run_configs,后续装饰器直接复用已生成的参数和ids,避免重复调用。

方式二:用缓存装饰器确保函数只执行一次

给_get_test_run_configs加上functools.lru_cache装饰器,让它缓存返回结果,重复调用时直接返回缓存值:

import time
import pytest
from functools import lru_cache

@lru_cache(maxsize=None)
def _get_test_run_configs():
    start_time = time.time()

    # 替换成你的实际逻辑,生成测试参数列表
    test_runs_list = [("design1", type('Run', (), {'name': 'run1'})(), "hash1"),
                      ("design2", type('Run', (), {'name': 'run2'})(), "hash2")]

    test_case_names = _generate_test_case_names(test_runs_list, str(start_time))
    return test_runs_list, test_case_names


def _generate_test_case_names(runs_list: list, start_time: str) -> list:
    test_case_names = []
    for design, run, run_hash in runs_list:
        run.name = f"{run.name}_{start_time}"
        test_case_names.append(run.name)
    return test_case_names


@pytest.mark.parametrize(
    "design, run, run_hash", _get_test_run_configs()[0], ids=_get_test_run_configs()[1]
)
def test_run_game_day(design, run, run_hash):
    assert True

注意:如果test_runs_list是动态生成的(比如依赖外部文件或环境变量),需要确保缓存的有效性,必要时可以清除缓存后再调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 12:45:24