【问题标题】:How can I mock/patch an associative array in python如何在 python 中模拟/修补关联数组
【发布时间】:2015-11-25 15:23:12
【问题描述】:

我有一个带有字典作为关联数组的模块来实现一种 switch 语句。

def my_method1():
    return "method 1"


def my_method2():
    return "method 2"


map_func = {
    '0': my_method1,
    '1': my_method2
}

def disptach(arg):
  return map_func[arg]()

如何在测试中模拟 my_method1?我尝试了以下方法但没有成功:

import my_module as app

@patch('my_module.my_method1')
def test_mocking_sample(self, my_mock):
    my_mock.return_value = 'mocked'
    assert_equal('mocked',app.dispatch('0'))

有什么想法吗?

【问题讨论】:

  • 我想你必须模拟 dispatch('0') 而不是 my_method1。这是使用 arg '0' 调用时的模拟调度。

标签: python unit-testing python-mock


【解决方案1】:

这段patch 文档说如下:

patch 通过(临时)更改名称指向的对象来工作 与另一个。可以有许多名称指向任何个人 对象,因此要使修补工作,您必须确保修补 被测系统使用的名称。

基本上,在应用补丁之前,您的调度员不会看到它,因为映射是为引用原始方法而构建的。

要使其可模拟,您可以做的最简单的事情是将映射折叠到 dispatch 函数中:

def dispatch(arg):
  return {
    '0': my_method1,
    '1': my_method2
  }[arg]()

这确实有一个缺点,即每次调用它时它都会重建该映射,因此它会更慢。

尝试变得有点聪明,似乎 Python 允许您交换函数的实际代码,如下所示:

>>> f = lambda: "foo"
>>> a = f
>>> g = lambda: "bar"
>>> f.func_code = g.func_code
>>> a()
'bar'

我不建议你这样做,但也许你可以找到一个支持类似东西的模拟框架。

【讨论】:

    【解决方案2】:

    正如您所发现的,修补 my_Method1() 不起作用。这是因为 map_func['0'] 是在导入 my_module 时定义的,随后对 my_Method1() 的更改不会为您的测试更新 map_func。相反,我们需要直接为键 '0' 修补字典 map_func 中的值。 unittest.mock documentation 解释了如何修补字典条目。以下是您的测试的有效实现:

    """ test_my_module.py
    """
    import unittest
    import unittest.mock as mock
    import my_module as app
    
    
    my_mock = mock.MagicMock()
    
    
    class Test_mock_sample(unittest.TestCase):
    
        @mock.patch.dict('my_module.map_func', {'0': my_mock})
        def test_mocking_sample(self):
            my_mock.return_value = 'mocked'
            self.assertEqual('mocked', app.dispatch('0'))
    
    if __name__ == '__main__':
        unittest.main()
    

    在您原来的 my_module 中将 disptach 更改为 dispatch 后...

    """ my_module.py
    """
    def my_method1():
        return "method 1"
    
    
    def my_method2():
        return "method 2"
    
    
    map_func = {
        '0': my_method1,
        '1': my_method2
    }
    
    def dispatch(arg):
      return map_func[arg]()
    

    然后命令python -m unittest test_my_module给出以下输出:

    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.000s
    
    OK
    

    成功了!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-24
      • 1970-01-01
      • 1970-01-01
      • 2020-09-30
      • 2022-07-06
      • 2017-07-05
      • 1970-01-01
      相关资源
      最近更新 更多