pytest.parametrize用list[tuple]传多组输入和预期结果,参数名须严格匹配;可用ids提升可读性,pytest.param支持标记跳过或预期失败,嵌套装饰器为顺序展开非笛卡尔积,fixture中需通过params和request.param复用参数化数据。

pytest.parametrize 怎么传多组输入和预期结果
直接用 pytest.mark.parametrize 装饰器,把测试数据和期望值一起塞进元组列表里,测试函数参数名必须和 parametrize 第一个字符串里的名字严格一致。
常见错误是参数名拼错、数据维度不匹配(比如传了 3 个输入但只写了 2 个参数名),或者把字典当元组传导致 TypeError: 'dict' object is not callable。
- 输入数据用
list[tuple]最稳妥,每项对应一次调用的全部参数 - 如果想让测试失败时显示更清晰的用例名,加
ids参数,比如ids=["add_1_2", "add_0_0"] - 避免在
parametrize里直接调用函数(如get_test_data()),否则所有用例会在收集阶段就执行一次——可能触发副作用或拖慢 pytest --collect-only
如何给不同参数组合打标签并条件跳过
用 pytest.param 包裹单条数据,再通过 marks 参数附加 pytest.mark.skipif 或 pytest.mark.xfail。
典型场景是:某组数据只在 Windows 下有效,或某个输入已知会抛 ValueError 且暂时不修复。
pytest.param(3, 4, 7, marks=pytest.mark.skipif(sys.platform == "win32", reason="not supported on Windows"))pytest.param("abc", marks=pytest.mark.xfail(raises=TypeError))- 注意
marks是关键字参数,不能写成位置参数;多个标记用列表,如marks=[pytest.mark.slow, pytest.mark.xfail]
parametrize 嵌套多层时为什么只跑 1 次而不是笛卡尔积
默认不会自动做笛卡尔积。两次 @pytest.mark.parametrize 装饰器叠加,是「外层循环 × 内层循环」,不是「每组外层配每组内层」。
比如对 a=[1,2] 和 b=["x","y"] 分别装饰,实际运行的是 4 个用例(1-x, 1-y, 2-x, 2-y)。但如果想表达「只测 (1,"x") 和 (2,"y") 这两组」,就必须显式写成一个 parametrize,传 [(1,"x"), (2,"y")]。
- 想强制笛卡尔积?得手动构造
itertools.product(a_list, b_list)再转 list - 嵌套装饰器容易让人误以为是“组合”,其实只是顺序展开,调试时建议先 print 出
request.node.callspec.id看实际生成的用例名 - 过度嵌套会让用例爆炸增长,CI 上容易超时,优先考虑合并参数或拆成独立测试函数
fixture 里怎么安全复用 parametrize 的数据
不能直接在 fixture 定义里用 @pytest.mark.parametrize —— 装饰器只对测试函数生效。正确做法是把参数化逻辑提到测试函数层,再通过 fixture 接收参数。
例如要为每组数据库配置启动一次连接,就把配置列表传进测试函数,再由 fixture 用 request.param 拿到当前用例的值。
- fixture 需声明
params=...并设scope="function",然后在 fixture 函数体里用request.param - 若 fixture 同时被多个测试函数使用,而它们的
parametrize数据不同,pytest 会报FixtureAlreadyUsed错误——此时必须用不同名字定义 fixture,或改用indirect控制传递方式 - 避免在 fixture 中做耗时初始化(如启动服务)后再参数化,否则每次参数变化都重来一遍;应把不变部分抽成 session-scoped fixture
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











