一条用例要吃多个 fixture,而 fixture 的返回值又得跟着参数变,关键就一句:parametrize 里的参数名,要和 fixture 的函数名对上,再用 indirect 把值交给 fixture,而不是直接传给测试函数。
推荐:indirect 分发给多个 fixture
python
import pytest
@pytest.fixture
def api_base_url(request):
mapping = {
"public": "https://api.example.com",
"internal": "https://api.internal.example",
"mock": "https://mock.example",
}
return mapping[request.param]
@pytest.fixture
def api_headers(request):
mapping = {
"public": {"Authorization": "Bearer public-token", "Content-Type": "application/json"},
"internal": {"Authorization": "Bearer internal-token", "Content-Type": "application/json"},
"mock": {"Authorization": "Bearer mock-token", "Content-Type": "text/plain"},
}
return mapping[request.param]
@pytest.mark.parametrize(
"api_base_url, api_headers",
[
("public", "public"),
("internal", "internal"),
("mock", "mock"),
],
indirect=["api_base_url", "api_headers"],
)
def test_openapi(api_base_url, api_headers):
assert "Authorization" in api_headers
assert api_base_url.startswith("https://")indirect 列出的名字会当成 fixture 来调,request.param 就是那一组里对应的值。
强相关就合成一个 fixture
URL 和 header 总是成对出现时,不必拆两个:
python
@pytest.fixture
def api_details(request):
table = {
"public": {
"url": "https://api.example.com",
"headers": {"Authorization": "Bearer public-token"},
},
"mock": {
"url": "https://mock.example",
"headers": {"Authorization": "Bearer mock-token"},
},
}
return table[request.param]
@pytest.mark.parametrize("api_details", ["public", "mock"], indirect=True)
def test_openapi(api_details):
assert api_details["url"].startswith("https://")
assert "Authorization" in api_details["headers"]indirect=True 表示这个参数整体交给同名 fixture。参数名和 fixture 名不一致时,pytest 不会按你想的那样传进去,这是最常见的踩坑。