如何使用Pytest fixture模拟requests.post测试多响应状态码
实现方案
要在不重复编码的前提下覆盖多响应状态码测试场景,直接用可传参的工厂模式fixture+pytest参数化即可,完全不需要重复编写mock逻辑:
- 首先改造原来的
MockResponse类,去掉写死的状态码、返回值属性,支持实例化时自定义状态码、响应体、错误响应文本,适配raise_for_status()的逻辑(非2xx状态码时自动抛HTTPError,和真实requests行为一致) - 把原来的固定mock fixture改成工厂函数形式,调用时可以按需传入需要模拟的状态码、自定义返回内容
- 用
pytest.mark.parametrize批量传入不同测试场景的参数,一次写完所有状态码的校验逻辑
改造后的test_app.py完整代码如下:
# test_app.py from typing import Dict, Union import pytest import requests from app import get_access_token class MockResponse: # 支持实例化时自定义状态码、返回json、错误文本 def __init__(self, status_code: int = 200, json_data: Dict = None, error_text: str = ""): self.status_code = status_code self.json_data = json_data or {} self.text = error_text def json(self) -> Dict[str, Union[str, int]]: return self.json_data def raise_for_status(self): # 对齐requests原生逻辑:非2xx状态码抛出HTTPError if not 200 <= self.status_code < 300: raise requests.exceptions.HTTPError(response=self) @pytest.fixture def mock_post_factory(monkeypatch): """生成自定义状态码的requests.post mock的工厂fixture""" def _factory(status_code: int = 200, json_data: Dict = None, error_text: str = ""): def mock_post(*args, **kwargs): return MockResponse(status_code=status_code, json_data=json_data, error_text=error_text) monkeypatch.setattr(requests, "post", mock_post) return _factory # 200成功场景校验返回值正确性 def test_get_access_token_success(mock_post_factory): test_json = { 'access_token': 'fake-access-token', 'token_type': 'fake-token-type', 'expires_in': 10800, } mock_post_factory(status_code=200, json_data=test_json) result = get_access_token( url="https://fakeurl", client_id="fake-client-id", client_secret="fake-client-secret", grant_type="fake-grant-type", ) assert result['access_token'] == "fake-access-token" assert result['token_type'] == "fake-token-type" assert result['expires_in'] == 10800 # 参数化批量测试所有异常状态码,无重复代码 @pytest.mark.parametrize( "status_code, err_text", [ (400, "invalid request param"), (401, "client auth failed"), (403, "permission denied"), (404, "token endpoint not found"), (500, "internal server error"), ] ) def test_get_access_token_http_error(mock_post_factory, status_code, err_text): mock_post_factory(status_code=status_code, error_text=err_text) with pytest.raises(requests.exceptions.HTTPError): get_access_token( url="https://fakeurl", client_id="fake-client-id", client_secret="fake-client-secret", grant_type="fake-grant-type", )
后续如果需要新增状态码测试,只需要在
parametrize的参数列表里追加对应的状态码和预期错误文本即可。如果要模拟特殊的返回结构,直接调用mock_post_factory时传入自定义的json_data就能适配,不需要修改fixture核心逻辑。
内容的提问来源于stack exchange,提问作者tandem
相关产品推荐
相关产品推荐

