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

如何在Python中覆盖/绕过测试用的Mock装饰器?

问题场景

我们的测试运行器全局Mock了外部服务(以Stripe为例)的方法,代码如下:

@mock.patch('services.Stripe.sync_customers', side_effect=mock_sync_customers)
def run_tests(self, test_labels, extra_tests=None, *args, **kwargs):
    return super().run_tests(test_labels, extra_tests, **kwargs)

现在需要让特定测试用例test_customers调用实际的API方法,而非Mock实现,同时不想给其他所有测试逐个添加装饰器(易出错)。

解决方案

方案1:在目标测试中临时恢复原方法(最简洁)

利用unittest.mock的上下文管理器,在测试方法内部临时覆盖全局Mock,恢复原方法的执行:

from unittest import mock
from services import Stripe
from django.test import TestCase

class YourTestCase(TestCase):
    def test_customers(self):
        # 获取原始方法
        original_sync = Stripe.sync_customers
        # 临时替换Mock为原始方法
        with mock.patch('services.Stripe.sync_customers', side_effect=original_sync):
            Company.objects.create(**customer_data)  # 这里会调用实际API
            # 后续添加你的断言逻辑

也可以用装饰器形式(适合不需要动态逻辑的测试):

from unittest import mock
from services import Stripe

class YourTestCase(TestCase):
    @mock.patch('services.Stripe.sync_customers', side_effect=Stripe.sync_customers)
    def test_customers(self, _):
        Company.objects.create(**customer_data)
        # 断言逻辑

方案2:修改测试运行器,根据测试属性跳过Mock

如果有多个测试需要使用真实服务,可以给这些测试标记特殊属性,然后在run_tests中判断是否跳过全局Mock:

  1. 给测试方法添加标记:
class YourTestCase(TestCase):
    def test_customers(self):
        self.use_real_stripe = True
        Company.objects.create(**customer_data)
  1. 修改测试运行器逻辑:
def run_tests(self, test_labels, extra_tests=None, *args, **kwargs):
    # 检查要运行的测试是否包含需要真实服务的用例
    use_real_stripe = False
    # 遍历测试用例(简化逻辑,实际需根据测试框架调整)
    for test_case in self.get_test_cases(test_labels, extra_tests):
        if hasattr(test_case, 'use_real_stripe') and test_case.use_real_stripe:
            use_real_stripe = True
            break
    
    if use_real_stripe:
        # 不应用Mock,直接运行测试
        return super().run_tests(test_labels, extra_tests, **kwargs)
    else:
        # 应用全局Mock
        with mock.patch('services.Stripe.sync_customers', side_effect=mock_sync_customers):
            return super().run_tests(test_labels, extra_tests, **kwargs)

方案3:临时停止全局Mock并恢复

如果全局Mock是通过装饰器添加的,可以在测试方法中获取Mock对象,临时停止并在测试结束后恢复:

class YourTestCase(TestCase):
    def test_customers(self):
        # 获取全局Mock对象
        mock_sync = mock.patch.object(services.Stripe, 'sync_customers').mock
        # 停止Mock,恢复原方法
        mock_sync.stop()
        try:
            Company.objects.create(**customer_data)
            # 断言逻辑
        finally:
            # 必须恢复Mock,避免影响其他测试
            mock_sync.start()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 06:01:08