如何对主要与3rd party APIs交互的Flask端点进行mock测试?
Flask中间层服务第三方API调用的Mock测试方案
核心思路是不用修改原有业务代码、也不需要重写端点,直接通过pytest-mock补丁替换你代码中调用第三方API的封装函数,既可以覆盖完整的路由参数校验、业务逻辑处理、返回值组装流程,又不会真实发起外部请求。
前置梳理:明确调用层级
你的代码中必然存在封装第三方API调用的独立函数/方法,示例结构如下:
# 第三方调用封装模块 例:third_parties/xxx_client.py import requests def query_xxx_service(user_id: str, req_data: dict) -> dict: resp = requests.post( "https://third-party-xxx.com/api/query", json=req_data, headers={"X-User-ID": user_id} ) resp.raise_for_status() return resp.json() # 路由模块调用上述封装 例:app/routes/xxx.py from third_parties.xxx_client import query_xxx_service @app.route("/api/v1/query-xxx", methods=["POST"]) def query_xxx_endpoint(): # 路由层参数校验 if not request.is_json: return {"error": "invalid request format"}, 400 req_data = request.get_json() if "biz_id" not in req_data: return {"error": "missing biz_id"}, 400 # 调用第三方API third_resp = query_xxx_service(request.headers.get("X-User-ID"), req_data) # 自定义返回值组装 return { "code": 0, "data": { "biz_id": req_data["biz_id"], "result": third_resp["result_data"] } }
你只需要在测试中mockquery_xxx_service这个函数即可,不需要修改路由层的任何逻辑。
具体实现步骤
安装依赖
pip install pytest-mock编写测试用例
# 测试用例文件 例:test_xxx_endpoint.py import requests def test_normal_query_flow(mocker, client): # 1. 补丁替换路由中引用的第三方调用函数 # 注意:patch路径是路由模块中import的路径,不是函数定义的原始路径,否则补丁不生效 mock_query = mocker.patch("app.routes.xxx.query_xxx_service") # 2. 预设第三方API的返回值 mock_query.return_value = {"result_data": "test_result", "extra_field": "xxx"} # 3. 正常调用测试客户端发起请求 resp = client.post( "/api/v1/query-xxx", json={"biz_id": "12345"}, headers={"X-User-ID": "u_67890"} ) # 4. 断言路由逻辑符合预期 assert resp.status_code == 200 resp_data = resp.get_json() assert resp_data["code"] == 0 assert resp_data["data"]["biz_id"] == "12345" assert resp_data["data"]["result"] == "test_result" # 5. 断言第三方调用参数符合预期,验证路由参数传递逻辑 mock_query.assert_called_once_with("u_67890", {"biz_id": "12345"}) def test_third_api_error_handling(mocker, client): # 模拟第三方接口报错的场景,验证异常处理逻辑 mock_query = mocker.patch("app.routes.xxx.query_xxx_service") mock_query.side_effect = requests.exceptions.HTTPError("500 Internal Server Error") resp = client.post( "/api/v1/query-xxx", json={"biz_id": "12345"}, headers={"X-User-ID": "u_67890"} ) assert resp.status_code == 503 assert "third party service unavailable" in resp.get_json()["error"]
复用优化:封装为fixture减少重复代码
如果多个测试用例需要用到同一个第三方API的mock,可以在conftest.py中封装为pytest fixture全局复用:
# conftest.py import pytest @pytest.fixture def mock_xxx_query(mocker): mock_func = mocker.patch("app.routes.xxx.query_xxx_service") mock_func.return_value = {"result_data": "default_test_result"} return mock_func
后续测试用例直接传入fixture即可使用,需要自定义返回值时单独修改即可:
def test_custom_response(mock_xxx_query, client): mock_xxx_query.return_value = {"result_data": "custom_value"} # 测试逻辑不变
内容的提问来源于stack exchange,提问作者JeffSpicoli
相关产品推荐
相关产品推荐

