如何让pytest.fixture参数化ID生成与pytest.mark.parametrize一致?
问题
使用参数化pytest.fixture时,默认的ID生成方式(如parametrized_fixture0这类命名)不够直观实用,希望改用@pytest.mark.parametrize的ID生成逻辑(比如将参数元组(1,2,3)生成为1-2-3)。已知fixture的ids参数可以传入可调用对象,想知道是否存在官方实现的可调用对象,替代自定义的get_id函数。
最小可复现示例(MRE)
test_ids.py代码
import pytest def add3(a, b, c): return a + b + c @pytest.mark.parametrize("a,b,c", [ (1, 2, 3), (4, 5, 6), ]) def test_add_with_parametrize(a, b, c): assert a + b + c == add3(a, b, c) @pytest.fixture(params=[(1, 2, 3), (4, 5, 6)]) def parametrized_fixture(request): return request.param def test_add_with_parametrized_fixture(parametrized_fixture): a, b, c = parametrized_fixture assert a + b + c == add3(a, b, c) def get_id(val): return f"{val!r}" @pytest.fixture(params=[(1, 2, 3), (4, 5, 6)], ids=get_id) def parametrized_fixture_bis(request): return request.param def test_add_with_parametrized_fixture_bis(parametrized_fixture_bis): a, b, c = parametrized_fixture_bis assert a + b + c == add3(a, b, c)
执行输出
pytest -v ============================= test session starts ============================= platform linux -- Python 3.11.11, pytest-8.3.5, pluggy-1.5.0 -- /home/vmonteco/.pyenv/versions/3.11.11/envs/3.11_pytest/bin/python cachedir: .pytest_cache rootdir: /home/vmonteco/code/MREs/MRE_pytest_ids collected 6 items test_ids.py::test_add_with_parametrize[1-2-3] PASSED [ 16%] test_ids.py::test_add_with_parametrize[4-5-6] PASSED [ 33%] test_ids.py::test_add_with_parametrized_fixture[parametrized_fixture0] PASSED [ 50%] test_ids.py::test_add_with_parametrized_fixture[parametrized_fixture1] PASSED [ 66%] test_ids.py::test_add_with_parametrized_fixture_bis[(1, 2, 3)] PASSED [ 83%] test_ids.py::test_add_with_parametrized_fixture_bis[(4, 5, 6)] PASSED [100%] ============================== 6 passed in 0.01s ==============================
解决方案
pytest没有直接暴露官方可调用对象来完全复刻@pytest.mark.parametrize的ID生成逻辑,但可以通过以下方式实现需求:
1. 复用pytest内部ID生成函数(注意版本兼容性)
@pytest.mark.parametrize内部使用的ID生成函数是_parametrize_make_id,可以从pytest.mark模块导入直接使用。但这属于pytest内部函数,后续版本可能会变动,不保证长期兼容性:
import pytest from pytest.mark import _parametrize_make_id @pytest.fixture(params=[(1, 2, 3), (4, 5, 6)], ids=_parametrize_make_id) def parametrized_fixture(request): return request.param
使用后生成的ID会和parametrize完全一致,比如1-2-3。
2. 自定义兼容逻辑(推荐,无兼容性风险)
如果不想依赖内部函数,可以自己实现和parametrize一致的ID生成逻辑,处理元组/列表时用-连接元素的repr:
import pytest def parametrize_style_id(val): if isinstance(val, (tuple, list)): return "-".join(repr(item) for item in val) return repr(val) @pytest.fixture(params=[(1, 2, 3), (4, 5, 6)], ids=parametrize_style_id) def parametrized_fixture(request): return request.param
3. 手动指定ID(适合参数较少的场景)
如果参数数量不多,也可以用pytest.Parameter为每个参数手动指定ID:
import pytest @pytest.fixture(params=[ pytest.Parameter((1, 2, 3), id="1-2-3"), pytest.Parameter((4, 5, 6), id="4-5-6") ]) def parametrized_fixture(request): return request.param
内容的提问来源于stack exchange,提问作者vmonteco
相关产品推荐
相关产品推荐

