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

Django单元测试:Mock外部API的正确方式是什么?

搞定Mock外部API的单元测试方案

嘿,我来帮你解决这个Mock外部API的问题!核心思路就是把utils.get_original_title_and_name这个调用外部API的函数给“替换”掉,让它在单元测试时不发起真实请求,而是返回我们预设的模拟数据,这样就能专注测试Book.save()的逻辑,完全不用依赖外部服务。

下面是具体的实现步骤和代码示例,我假设你用的是Django测试框架(毕竟是Django模型):

1. 先导入测试需要的工具

在你的测试文件(比如tests/test_models.py)里,先把需要的模块导进来:

from django.test import TestCase
from unittest.mock import patch
from .models import Book
from . import utils

2. 编写测试用例:Mock掉外部API调用

我们可以用@patch装饰器或者上下文管理器with patch(...)来临时替换目标函数,两种方式都好用,看你偏好哪种。

场景1:测试有ISBN且API返回数据的情况

class BookModelTest(TestCase):
    def test_save_with_isbn_and_valid_api_response(self):
        # 用上下文管理器Mock掉utils里的那个API调用函数
        with patch('你的app名.utils.get_original_title_and_name') as mock_api_call:
            # 给Mock函数设置预设的返回值,模拟API返回的有效数据
            mock_api_call.return_value = {
                'author': 'J.K. Rowling',
                'title': 'Harry Potter and the Philosopher\'s Stone'
            }
            
            # 创建一个带ISBN的Book实例
            book = Book(
                title='哈利波特与魔法石(中文版)',
                isbn='9780747532743'
            )
            # 调用save方法
            book.save()
            
            # 验证Mock函数确实被调用了,而且传入的ISBN是对的
            mock_api_call.assert_called_once_with('9780747532743')
            # 验证save之后,original_author被正确赋值了
            self.assertEqual(book.original_author, 'J.K. Rowling')

场景2:测试有ISBN但API没返回数据的情况

def test_save_with_isbn_but_empty_api_response(self):
        with patch('你的app名.utils.get_original_title_and_name') as mock_api_call:
            # 让Mock函数返回None,模拟API没查到数据的情况
            mock_api_call.return_value = None
            
            book = Book(
                title='自定义书名',
                isbn='1234567890123'
            )
            book.save()
            
            # 验证API确实被调用了,但original_author还是空的
            mock_api_call.assert_called_once_with('1234567890123')
            self.assertIsNone(book.original_author)

场景3:测试没有ISBN的情况(完全不调用API)

def test_save_without_isbn(self):
        with patch('你的app名.utils.get_original_title_and_name') as mock_api_call:
            book = Book(
                title='一本没有ISBN的书'
            )
            book.save()
            
            # 验证API函数根本没被调用过
            mock_api_call.assert_not_called()

几个关键注意点

  • Mock的路径一定要对:你得patch函数被实际调用的那个路径!比如在Book.save()里,是从.utils导入的get_original_title_and_name,所以要patch你的app名.utils.get_original_title_and_name,千万别写错路径,不然Mock会失效。
  • 灵活控制Mock的返回值:除了return_value,你还可以用side_effect来模拟异常(比如API请求失败的情况),覆盖更多业务场景。
  • 验证调用情况:用assert_called_once_with()、assert_not_called()这些方法,确保你的Mock函数被正确调用,参数也符合预期,这样能保证测试的严谨性。

这样一来,你就能完全隔离外部API的影响,专心测试save()方法的逻辑正确性啦!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:47:13