【问题标题】:How to mock objects of a Python class?如何模拟 Python 类的对象?
【发布时间】:2018-05-11 14:15:04
【问题描述】:

假设我是以下班级;

class CompositionClass(object):
    def __init__(self):
        self._redis = Redis()
        self._binance_client = BinanceClient()

    def do_processing(self, data):
        self._redis.write(data)
        self._binance_client.buy(data.amount_to_buy)

        # logic to actually unittest

        return process_val

我的ComplexClass 中有其他对象调用外部API 作为组合。当我对do_processing 的逻辑进行单元测试时,我不想调用这些昂贵的 API 调用。我已经在 SO 和 Google 中彻底检查了单元测试;所有的例子都很简单,不是很有用。就我而言,如何使用 unittest.mock 模拟这些对象?

【问题讨论】:

    标签: python-3.x mocking python-unittest


    【解决方案1】:

    模拟RedisBinanceClient 类的一种方法是在测试类中使用patch 装饰器,例如:

    from unittest import TestCase
    from unittest.mock import patch
    from package.module import CompositionClass
    
    class TestCompositionClass(TestCase):
    
        @patch('package.module.BinanceClient')
        @patch('package.module.Redis')
        def test_do_processing(self, mock_redis, mock_binance):
            c = CompositionClass()
            data = [...]
            c.do_processing(data)
    
            # Perform your assertions
    
            # Check that mocks were called
            mock_redis.return_value.write.assert_called_once_with(data)
            mock_binance.return_value.buy.assert_called_once_with(data.amount_to_buy)
    

    请注意,指定给@patch 的路径是包含CompositionClass 及其对RedisBinanceClient 的导入的模块的路径。修补发生在该模块中,而不是包含 RedisBinanceClient 实现本身的模块。

    【讨论】:

    • 非常感谢 :) 按预期工作 :)
    【解决方案2】:

    您需要为此函数设置一个必须由 API 调用返回的值:

    from unittest.mock import MagicMock
    
    
    class Tester(unittest.TestCase):
        def setUp(self):
            pass
    
        def test_do_processing(self):
    
            self.API_function = MagicMock(return_value='API_response')
            # test logic
    

    【讨论】:

    • 这将如何工作? unittest.mock 如何知道要模拟特定功能?因为我们没有指定它?是self.API_function = self._redis
    • 它可以是任何函数self._redis.wait = MagicMock(...)self._binance_client.buy = MagicMock(..)或任何其他函数。您只需设置一个替换对函数的实际调用的值。
    • 对不起,它不起作用;它说Tester object has no attribute _redis.wait
    • API_function替换成你的函数名
    • 是的,我做了它不起作用。我更新了我的评论
    猜你喜欢
    • 2022-10-17
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多