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

如何使用Mock编写单元测试验证调用第三方API的Flask接口

解决Flask接口单元测试中Mock第三方API的问题

我先帮你梳理下现有代码里的问题,然后给出正确的Mock实现方式:

第一步:修复Flask接口代码的逻辑问题

你的接口代码里有个明显的逻辑错误:return r.json()["currentDateTime"]之后的代码永远不会被执行,而且还误用了未定义的response变量。先把接口代码修正为:

import requests
from flask import Flask, request, jsonify, make_response

app = Flask(__name__, template_folder="templates")

@app.route('/get_time', methods=['GET'])
def get_time():
    try:
        time_zone = request.args.get('time_zone')
        if not time_zone:  # 新增:校验时区参数是否存在
            return make_response(jsonify({"Error": "time_zone parameter is required"}), 400)
            
        url = f"http://worldclockapi.com/api/json/{time_zone}/now"
        r = requests.get(url)
        r.raise_for_status()  # 触发HTTP错误的异常,比如404/500等
        return r.json()["currentDateTime"]
    except requests.exceptions.RequestException as e:
        # 捕获请求相关的异常(比如连接失败、HTTP错误)
        return make_response(jsonify({"Error": str(e)}), 400)
    except Exception as e:
        # 捕获其他未知异常
        return make_response(jsonify({"Error": "Unexpected error occurred"}), 500)

if __name__ == '__main__':
    app.run(debug=True)

第二步:正确编写单元测试和Mock逻辑

你的测试代码存在几个问题:测试方法名不符合unittest规范(必须以test_开头)、没有使用Flask测试客户端调用接口、Mock路径不正确,还有未正确获取接口响应。下面是修正后的测试代码:

import json
import unittest
from unittest.mock import patch
import requests
from timeofday import app  # 导入你的Flask应用实例

class MockResponse:
    def __init__(self, json_data, status_code):
        self.json_data = json_data
        self.status_code = status_code

    def json(self):
        return self.json_data

    def raise_for_status(self):
        # 模拟requests的raise_for_status方法,状态码异常时抛出错误
        if self.status_code >= 400:
            raise requests.exceptions.HTTPError(f"HTTP Error {self.status_code}")

def mock_requests_get_success(*args, **kwargs):
    # 模拟第三方API成功响应
    return MockResponse(
        json_data={
            "currentDateTime": "2019-11-08T15:52-05:00",
            "utcOffset": "-05:00:00",
            "isDayLightSavingsTime": False,
            "dayOfTheWeek": "Friday",
            "timeZoneName": "Eastern Standard Time"
        },
        status_code=200
    )

def mock_requests_get_failure(*args, **kwargs):
    # 模拟第三方API失败响应(比如404)
    return MockResponse(
        json_data={"Error": "Time zone not found"},
        status_code=404
    )

class TestGetTimeAPI(unittest.TestCase):
    def setUp(self):
        # 创建Flask测试客户端,开启测试模式
        self.client = app.test_client()
        self.client.testing = True

    @patch('timeofday.requests.get')  # 关键:Mock的是Flask文件中导入的requests.get
    def test_get_time_success(self, mock_get):
        # 配置Mock返回成功响应
        mock_get.side_effect = mock_requests_get_success

        # 调用Flask接口
        response = self.client.get('/get_time?time_zone=est')

        # 断言响应状态码和内容
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data.decode('utf-8'), "2019-11-08T15:52-05:00")

        # 断言第三方API被正确调用
        mock_get.assert_called_once_with("http://worldclockapi.com/api/json/est/now")

    @patch('timeofday.requests.get')
    def test_get_time_missing_timezone(self, mock_get):
        # 调用接口时不传time_zone参数
        response = self.client.get('/get_time')

        self.assertEqual(response.status_code, 400)
        self.assertIn("time_zone parameter is required", response.json["Error"])

        # 此时第三方API不应该被调用
        mock_get.assert_not_called()

    @patch('timeofday.requests.get')
    def test_get_time_api_failure(self, mock_get):
        # 配置Mock返回失败响应
        mock_get.side_effect = mock_requests_get_failure

        response = self.client.get('/get_time?time_zone=invalid_zone')

        self.assertEqual(response.status_code, 400)
        self.assertIn("HTTP Error 404", response.json["Error"])

if __name__ == '__main__':
    unittest.main()

关键知识点说明

  • Mock路径的正确性:当你在Flask文件(比如timeofday.py)里导入requests并调用requests.get时,必须Mocktimeofday.requests.get,而不是全局的requests.get——unittest.mock的patch是基于模块的导入路径来替换对象的。
  • 使用Flask测试客户端:通过app.test_client()可以模拟HTTP请求调用接口,完整测试接口的逻辑流程,包括参数校验、异常处理等。
  • 覆盖多场景测试:除了成功场景,还要测试参数缺失、第三方API失败等异常情况,确保接口的错误处理逻辑正常工作。
  • 验证Mock调用:用mock_get.assert_called_once_with(...)可以确认第三方API是否被传入正确的参数调用,保证接口URL拼接逻辑正确。

内容的提问来源于stack exchange,提问作者Fagner Schuindt Caetano

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:40:08