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

如何使用unittest.mock模拟Python类的组合依赖对象?

用unittest.mock模拟外部依赖做单元测试

兄弟,这事儿我熟——单元测试碰到外部API调用就头疼,慢还容易失败,用unittest.mock完全能解决,我给你两种直接能用的方案,一步步来:

核心思路

本质就是把你的CompositionClass里的_redis和_binance_client这两个外部依赖给“掉包”,用mock对象冒充它们。这样调用write或者buy方法时,不会真的去连Redis或者Binance API,只会记录调用的参数和次数,完全不影响外部服务。

方案一:直接替换实例属性

这种方法简单直接,先创建被测类的实例,再手动把它的依赖属性换成mock对象:

import unittest
from unittest.mock import Mock
from your_module import CompositionClass  # 替换成你的实际模块路径

class TestCompositionClass(unittest.TestCase):
    def test_do_processing(self):
        # 1. 创建被测类的实例
        processor = CompositionClass()
        
        # 2. 把外部依赖换成Mock对象
        processor._redis = Mock()
        processor._binance_client = Mock()
        
        # 3. 构造测试用的数据
        test_data = {"amount_to_buy": 10, "key": "test_value"}
        
        # 4. 调用要测试的业务方法
        result = processor.do_processing(test_data)
        
        # 5. 验证业务逻辑的返回值(替换成你预期的process_val)
        self.assertEqual(result, expected_process_val)
        
        # 6. 验证外部依赖的方法是否被正确调用了
        processor._redis.write.assert_called_once_with(test_data)
        processor._binance_client.buy.assert_called_once_with(10)

方案二:用@patch装饰器模拟依赖类

这种方法更优雅,不用手动替换属性,直接通过装饰器模拟依赖类的导入,让被测类初始化时自动用mock实例:

import unittest
from unittest.mock import patch
from your_module import CompositionClass

class TestCompositionClass(unittest.TestCase):
    # 注意装饰器的顺序:从下往上对应参数顺序,先写的是最后一个参数
    @patch('your_module.Redis')
    @patch('your_module.BinanceClient')
    def test_do_processing(self, mock_binance_cls, mock_redis_cls):
        # 1. 获取mock实例(因为Redis()和BinanceClient()会返回mock对象)
        mock_redis = mock_redis_cls.return_value
        mock_binance = mock_binance_cls.return_value
        
        # 2. 创建被测类实例,此时内部的_redis和_binance_client都是mock的
        processor = CompositionClass()
        
        # 3. 构造测试数据
        test_data = {"amount_to_buy": 10, "key": "test_value"}
        
        # 4. 调用业务方法
        result = processor.do_processing(test_data)
        
        # 5. 验证返回值
        self.assertEqual(result, expected_process_val)
        
        # 6. 验证mock方法的调用情况
        mock_redis.write.assert_called_once_with(test_data)
        mock_binance.buy.assert_called_once_with(10)

关键注意点

  • patch路径别写错:要patch的是CompositionClass所在模块中导入的依赖类,而不是依赖类本身的模块。比如你的CompositionClass在myapp/trader.py里,导入的是from redis import Redis,那patch的路径就是myapp.trader.Redis,别直接写redis.Redis,不然会不生效!
  • 模拟返回值:如果业务逻辑依赖外部调用的返回结果,比如需要判断redis.write是否成功,你可以给mock方法设置返回值:mock_redis.write.return_value = True,这样代码里就能拿到预设的值。
  • 更多断言方法:除了assert_called_once_with,还有assert_called_with(验证最后一次调用的参数)、assert_not_called(确保方法没被调用),按需使用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:21:07