如何在python中模拟/修补关联数组

时间:2015-08-31 14:37:54

标签: python unit-testing python-mock

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

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'))

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

这篇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'

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

答案 1 :(得分:1)

正如您所发现的那样,修补my_Method1()不起作用。这是因为在导入my_module时定义了map_func['0'],并且对my_Method1()的后续更改未针对您的测试更新map_func。相反,我们需要直接修补密钥map_func的字典'0'中的值。 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

有效!