为何@pytest.fixture作为测试参数传入却未被调用?
为什么pytest fixture传入测试却不用调用也能生效?
这是pytest fixture的核心特性之一:只要测试函数将fixture声明为参数,无论是否显式调用它,fixture的完整生命周期都会自动执行。
具体到你看到的assert_live fixture:
这个fixture用了yield关键字,属于「带验证逻辑的fixture」:
yield之前的代码会在测试函数执行前运行(这里yield前没有代码,所以测试前无额外操作)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
相关产品推荐
相关产品推荐

