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
相关产品推荐
相关产品推荐

