【问题标题】:Should python unittest mock calls copy passed arguments by reference?python unittest mock调用是否应该通过引用复制传递的参数?
【发布时间】:2021-08-26 22:10:42
【问题描述】:

以下代码 sn-ps 均以python 3.7.11 运行。

我在 unittest.mock Mock 类中遇到了一些意外行为。我编写了一个单元测试,其中使用特定参数调用了 Mock,以涵盖在实际运行时预计会调用被模拟的真实对象的情况。测试通过了,所以我将构建推送到一个真实运行的设备上,以发现一个错误,即并非所有参数都传递给真实对象方法。我很快发现了我的错误,但对我来说,最初看起来我的单元测试应该失败了,而它却成功了。以下是该情况的一些简化示例。我很好奇的是,这种行为是否应该被视为我的错误或理解错误。


from `unittest.mock` import Mock

mock = Mock()
l = [1]
mock(l)

l.append(2)

mock.call_args
# Output: call([1,2]) 
# rather than call([1])

id(l) == id(mock.call_args[0][0])
# Output: True 
# This means the l object and latest call_args reference occupy the same space in memory

这种按引用复制的行为令人困惑,因为当在同一个过程中调用函数时,预计不会在调用后将参数附加到对象中来调用该函数。


def print_var(x):
     print(x)

l = [1]
print_var(l)
# Output: 1

l.append(2)
# print_var never be called with [1,2]

call_args 使用 deepcopy 来模拟我所期望的行为是否有意义?

【问题讨论】:

  • 不,一直这样做是低效的(而且可能并不总是有效):bugs.python.org/issue32632mock.assert_called_once_with([1]) 没有这个问题。
  • mock.assert_called_once_with([1]) 在上面的例子中会失败,输出AssertionError: Expected call: mock([1]) Actual call: mock([1, 2])
  • 您提供的链接确实帮助我找到了解决方案,谢谢docs.python.org/3/library/unittest.mock-examples.html

标签: python-3.x unit-testing mocking


【解决方案1】:

unittest.mock examples找到解决方案


from unittest.mock import Mock
from copy import deepcopy
class CopyingMock(MagicMock):
    def __call__(self, *args, **kwargs):
        args = deepcopy(args)
        kwargs = deepcopy(kwargs)
        return super().__call__(*args, **kwargs)

c = CopyingMock(return_value=None)
arg = set()
c(arg)
arg.add(1)
c.assert_called_with(set())
c.assert_called_with(arg)
# Traceback (most recent call last):
#    ...
# AssertionError: Expected call: mock({1})
# Actual call: mock(set())

【讨论】:

    猜你喜欢
    • 2013-11-08
    • 2014-03-08
    • 2021-05-20
    • 2010-10-10
    • 1970-01-01
    • 2017-06-12
    相关资源
    最近更新 更多