You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何@pytest.fixture作为测试参数传入却未被调用?

为什么pytest fixture传入测试却不用调用也能生效?

这是pytest fixture的核心特性之一:只要测试函数将fixture声明为参数,无论是否显式调用它,fixture的完整生命周期都会自动执行。

具体到你看到的assert_live fixture:

这个fixture用了yield关键字,属于「带验证逻辑的fixture」:

  1. yield之前的代码会在测试函数执行前运行(这里yield前没有代码,所以测试前无额外操作)
  2. yield之后的代码会在测试函数执行完成后自动运行,不管测试是成功还是失败(只要fixture被触发)

所以assert_live里的断言,会在test_auth_failure测试跑完后自动执行,验证请求的variables是否符合直播场景的参数格式——根本不需要在测试函数里调用它,声明参数只是告诉pytest要触发这个fixture的执行。

同文件里的mock fixture也是同样逻辑:

mock fixture中yield mock之后的那些断言(比如assert mock.called_once、校验请求payload结构),都是在测试结束后自动执行的。测试函数里只是用到了mock对象本身,后续的验证逻辑完全由fixture接管。

这种写法的好处:

把重复的验证逻辑抽成fixture,避免在每个测试里写冗余代码,同时让测试函数只专注于核心的测试场景(比如这里的test_auth_failure只需要处理授权失败的断言,请求格式的验证交给fixture统一处理)。


附相关代码(中文注释版):

# 其他上下文/连续性相关的fixture
@pytest.fixture
def mocker(self):
    # 内置的requests_mock fixture在引用后续常量或类时表现不佳
    with requests_mock.Mocker() as mocker:
        mocker.register_uri(requests_mock.ANY, requests_mock.ANY, exc=requests_mock.exceptions.InvalidRequest)
        yield mocker

@pytest.fixture
def mock(self, request, mocker: requests_mock.Mocker):
    mock = mocker.post("https://gql.twitch.tv/gql", **getattr(request, "param", {"json": {}}))
    yield mock
    # 测试结束后自动执行的断言
    assert mock.called_once
    payload = mock.last_request.json()  # type: ignore[union-attr]
    assert tuple(sorted(payload.keys())) == ("extensions", "operationName", "variables")
    assert payload.get("operationName") == "PlaybackAccessToken"
    assert payload.get("extensions") == {
        "persistedQuery": {
            "sha256Hash": "0828119ded1c13477966434e15800ff57ddacf13ba1911c129dc2200705b0712",
            "version": 1,
        },
    }

# 令人困惑的fixture
@pytest.fixture
def assert_live(self, mock):
    yield
    # 测试结束后自动执行的断言,验证请求变量是否符合直播场景
    assert mock.last_request.json().get("variables") == {  # type: ignore[union-attr]
        "isLive": True,
        "isVod": False,
        "login": "channelname",
        "vodID": "",
        "playerType": "embed",
    }

# 令人困惑的测试
# 注意:assert_live被作为参数传入,但并未显式调用
@pytest.mark.parametrize("plugin,mock", [
    (
        [("api-header", [("Authorization", "OAuth invalid-token")])],
        {
            "status_code": 401,
            "json": {"error": "Unauthorized", "status": 401, "message": "The \"Authorization\" token is invalid."},
        },
    ),
], indirect=True)
def test_auth_failure(self, caplog: pytest.LogCaptureFixture, plugin: Twitch, mock: requests_mock.Mocker, assert_live):
    with pytest.raises(NoStreamsError) as cm:
        plugin._access_token(True, "channelname")
    assert str(cm.value) == "No streams found on this URL: https://twitch.tv/channelname"
    assert mock.last_request._request.headers["Authorization"] == "OAuth invalid-token"  # type: ignore[union-attr]
    assert [(record.levelname, record.module, record.message) for record in caplog.records] == [
        ("error", "twitch", "Unauthorized: The \"Authorization\" token is invalid."),
    ]

内容的提问来源于stack exchange,提问作者theChoosyBeggar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 12:05:29