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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:45:34