如何将@pytest.fixture()与@pytest.mark.parametrize()结合使用
问题分析与解决方案
你的错误根源在于对@pytest.mark.parametrize和@pytest.fixture的结合逻辑理解有误:
- 直接在parametrize的参数值里写
dict_used_by_many_tests,本质是把fixture的函数本身当成了测试参数值,而不是fixture生成的字典对象,所以会触发TypeError: 'function' object is not subscriptable。 - pytest禁止直接调用fixture函数,因为fixture的生命周期由pytest管理,手动调用会破坏其依赖注入逻辑,所以会报
Fixtures are not meant to be called directly。
下面提供两种常见的正确结合方式:
方式一:fixture提供固定数据,parametrize参数化测试变量
如果你的需求是复用同一个字典,批量测试不同的key和预期值,直接让fixture作为测试函数的参数注入,同时用parametrize参数化key和预期结果即可:
import pytest def foo(data, key): return data[key] @pytest.fixture() def dict_used_by_many_tests(): return {"name": "Dionysia", "age": 28, "location": "Athens"} @pytest.mark.parametrize( "key, expected", [ ("name", "Dionysia"), ("age", 28), ("location", "Athens"), ], ) def test_foo_one(dict_used_by_many_tests, key, expected): actual = foo(dict_used_by_many_tests, key) assert actual == expected
方式二:parametrize参数化fixture的返回值
如果需要批量测试不同的字典数据,可以给fixture添加参数,配合indirect=True让pytest将parametrize中的参数解析为fixture的输入:
import pytest def foo(data, key): return data[key] @pytest.fixture() def dict_used_by_many_tests(request): # 根据parametrize传入的标识返回对应字典 test_datasets = { "user1": {"name": "Dionysia", "age": 28, "location": "Athens"}, "user2": {"name": "Socrates", "age": 70, "location": "Athens"} } return test_datasets[request.param] @pytest.mark.parametrize( "dict_used_by_many_tests, key, expected", [ ("user1", "name", "Dionysia"), ("user2", "name", "Socrates"), ], indirect=["dict_used_by_many_tests"] # 指定该参数为fixture,由pytest调用注入 ) def test_foo_one(dict_used_by_many_tests, key, expected): actual = foo(dict_used_by_many_tests, key) assert actual == expected
额外说明
如果只是想复用单个字典数据,完全不需要用parametrize包裹fixture——fixture本身的设计目的就是复用测试依赖数据,parametrize则是用来生成多组测试用例的,二者各司其职。
内容的提问来源于stack exchange,提问作者maxvd
相关产品推荐
相关产品推荐

