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

FastAPI单元测试:如何用预定义响应替换远程API返回

FastAPI单元测试替换第三方API响应的实现方案

完全可以在测试场景下用预定义模拟响应替换真实远程调用结果,这是后端接口单元测试隔离外部依赖的标准实践,不需要发起真实外网请求,还能覆盖各类正常、异常返回场景。

方案1:零业务代码改动,通过mock打桩替换远程调用

你现有代码不需要做任何调整,直接用Python标准库unittest.mock(搭配pytest使用更便捷)拦截远程调用逻辑,返回预设响应即可,支持单次请求触发多次远程调用的场景。

核心实现逻辑

你封装的call_api方法底层用requests.get发起请求,只需要在测试时把requests.get(或者你封装的API.call_api方法)替换为mock对象,就能完全控制返回结果,还能校验调用参数、调用次数是否符合预期。

示例代码

from fastapi.testclient import TestClient
from unittest.mock import Mock, patch
from web_api import app

client = TestClient(app)

def test_stuff_interface():
    # 构造和真实requests.Response行为一致的模拟响应
    mock_resp_success1 = Mock()
    mock_resp_success1.status_code = 200
    mock_resp_success1.json.return_value = {"things": [{"id": 1, "name": "item1"}, {"id": 2, "name": "item2"}]}
    mock_resp_success1.raise_for_status = Mock()  # 不抛异常代表请求成功

    mock_resp_success2 = Mock()
    mock_resp_success2.status_code = 200
    mock_resp_success2.json.return_value = {"things": [{"id": 3, "name": "item3"}]}
    mock_resp_success2.raise_for_status = Mock()

    # patch路径必须写业务代码中实际引用requests的模块路径,否则mock不生效
    # 比如你的API类定义在web_api.api_client模块,路径就写"web_api.api_client.requests.get"
    with patch("web_api.requests.get") as mock_get:
        # 多次调用场景下,side_effect传入列表可按调用顺序返回不同响应
        # 也可以传入函数,根据url、params参数动态返回对应结果
        mock_get.side_effect = [mock_resp_success1, mock_resp_success2]

        # 发起对自有接口的请求
        resp = client.get("/stuff/", params={"param1": "test"})

        # 校验自有接口返回符合预期
        assert resp.status_code == 200
        # 补充你自己的业务返回断言,比如返回的item数量、字段值等

        # 可选:校验远程调用逻辑是否正确
        assert mock_get.call_count == 2  # 验证确实触发了2次远程调用
        first_call_url = mock_get.call_args_list[0][0][0]
        assert "something" in first_call_url  # 验证请求endpoint拼接正确

如果要模拟第三方接口报错场景,只需要让mock对象的raise_for_status抛出对应异常即可:

from requests.exceptions import HTTPError
mock_resp_error = Mock()
mock_resp_error.status_code = 500
mock_resp_error.raise_for_status.side_effect = HTTPError("第三方服务异常")

方案2:mock自定义API类方法,粒度更贴合业务

如果觉得直接mockrequests层太底层,可以直接拦截你自己封装的API.call_api方法,不需要关心requests的底层细节,写法更简洁:

def test_stuff_interface_mock_api_method():
    with patch("web_api.API.call_api") as mock_call_api:
        mock_resp = Mock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"things": [{"id": 1, "name": "test_item"}]}
        mock_resp.raise_for_status = Mock()
        mock_call_api.return_value = mock_resp

        resp = client.get("/stuff/", params={"test": "value"})
        assert resp.status_code == 200
        # 补充业务断言

实践注意点

  • 注意patch路径正确性:必须mock业务代码中实际使用的对象引用路径,而不是第三方库本身的路径,这是mock不生效的最常见原因。
  • 公共mock逻辑抽成fixture:如果多个测试用例都需要模拟第三方API,可以用pytest的fixture封装mock逻辑,减少重复代码。
  • 覆盖全部分支场景:通过mock可以自由构造空返回、字段缺失、权限错误、服务不可用等各类极端响应,覆盖自有代码的所有异常处理分支,这是调用真实第三方接口无法稳定做到的。
  • 不要在单元测试中发起真实第三方请求:网络波动、第三方服务限流/宕机、测试数据污染都会导致测试结果不稳定,违背单元测试隔离依赖的原则。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:18:20