Skip to content

一条用例要吃多个 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 不会按你想的那样传进去,这是最常见的踩坑。

测试开发工程师 · 专注自动化与系统架构 | 邮箱: hansblog@atumsoul.win