Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何模拟对接收可变对象作为参数的函数的调用?_Python_Mocking - Fatal编程技术网

Python 如何模拟对接收可变对象作为参数的函数的调用?

Python 如何模拟对接收可变对象作为参数的函数的调用?,python,mocking,Python,Mocking,举个例子: def func_b(a): print a def func_a(): a = [-1] for i in xrange(0, 2): a[0] = i func_b(a) 以及尝试测试函数a和模拟函数b的测试函数: import mock from mock import call def test_a(): from dataTransform.test import func_a with mock

举个例子:

def func_b(a):
    print a

def func_a():
    a = [-1]
    for i in xrange(0, 2):
        a[0] = i
        func_b(a)
以及尝试测试函数a和模拟函数b的测试函数:

import mock
from mock import call

def test_a():
    from dataTransform.test import func_a
    with mock.patch('dataTransform.test.func_b', autospec=True) as func_b_mock:
        func_a()
        func_b_mock.assert_has_calls([call(0), call(1)])
在func_a执行后,我尝试测试func_a是否正确调用func_b,但由于在for循环中,我最终对列表进行了修改,我得到:

AssertionError: Calls not found.
Expected: [call(0), call(1)]
Actual: [call([1]), call([1])]
下面的工作(从
unittest
导入
mock
是Python 3的一部分,
模块
func\u a
func\u b
的地方):

这继承自
MagicMock
,并重新定义调用行为以深度复制参数和关键字参数

def test_a():
    from module import func_a
    with mock.patch('module.func_b', new_callable=ModifiedMagicMock) as func_b_mock:
        func_a()
        func_b_mock.assert_has_calls([call([0]), call([1])])
您可以使用
new\u callable
参数将新类传递到
patch
中,但是它不能与
autospec
共存。请注意,您的函数使用列表调用
func\u b
,因此
call(0)、call(1)
必须更改为
call([0])、call([1])
。当通过调用
test\u a
运行时,此操作不会执行任何操作(通过)

现在我们不能同时使用
new\u callable
autospec
,因为
new\u callable
是一个通用工厂,但在我们的例子中只是一个
MagicMock
覆盖。但这是一个非常酷的
mock
功能,我们不想失去它

我们需要的是将
MagicMock
替换为
ModifiedMagicMock
仅用于我们的测试:我们希望避免更改所有测试的
MagicMock
行为。。。可能很危险。我们已经有了一个工具来完成它,它是
patch
,与
new
参数一起用于替换目标

在这种情况下,我们使用decorator来避免太多缩进并使其更具可读性:

@mock.patch('module.func_b', autospec=True)
@mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a(func_b_mock):
    from module import func_a
    func_a()
    func_b_mock.assert_has_calls([call([0]), call([1])])
或:


您对
func_b()
的模拟将需要复制或以其他方式不可接触地表示它所获得的参数。然后,您可以稍后检查这些副本的值。这是否回答了您的问题?谢谢在Python2.7中,对父函数的调用应该是这样的:return super(ModifiedMagicMock,_mock_self)。_mock_call(*copy.deepcopy(args),**kwargs)对不起,我忘了。。。几个月前我就写了一个答案☺.我知道解决这个漏洞的方法。如果你同意,我可以再次编辑你的答案,否则我可以提交一个新的答案来涵盖它。我讨厌失去autospec功能。@matsjoyce我可以使用装饰器而不是语句。。。“它更可编辑。”米歇尔·阿米科,谢谢。出于某种原因(嘲笑是聪明的),只有当我颠倒了装饰者的顺序时,它才起作用。我用half decorator版本添加了半个
,以防模拟的实现发生变化。
@mock.patch('module.func_b', autospec=True)
@mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a(func_b_mock):
    from module import func_a
    func_a()
    func_b_mock.assert_has_calls([call([0]), call([1])])
@mock.patch("mock.MagicMock", new=ModifiedMagicMock)
def test_a():
    with mock.patch('module.func_b') as func_b_mock:
        from module import func_a
        func_a()
        func_b_mock.assert_has_calls([call([0]), call([1])])