首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >相同的模拟调用链是否总是返回完全相同的模拟对象?

相同的模拟调用链是否总是返回完全相同的模拟对象?
EN

Stack Overflow用户
提问于 2019-08-20 14:30:22
回答 1查看 329关注 0票数 1

代码:

代码语言:javascript
运行
复制
from unittest.mock import Mock

mock = Mock()

print('mock.f():', id(mock.f()))
print('mock.f().g().h():', id(mock.f().g().h()))
print('mock():', id(mock()))
print('mock().f():', id(mock().f()))
print()

print('mock.f():', id(mock.f()))
print('mock.f().g().h():', id(mock.f().g().h()))
print('mock():', id(mock()))
print('mock().f():', id(mock().f()))
print()

print('mock.f(1):', id(mock.f(1)))
print('mock.f(2).g(3).h(4):', id(mock.f(2).g(3).h(4)))
print('mock(5):', id(mock(5)))
print('mock(6).f(7):', id(mock(6).f(7)))
print()

输出:

代码语言:javascript
运行
复制
mock.f(): 4483288208
mock.f().g().h(): 4483354192
mock(): 4483368976
mock().f(): 4483708880

mock.f(): 4483288208
mock.f().g().h(): 4483354192
mock(): 4483368976
mock().f(): 4483708880

mock.f(1): 4483288208
mock.f(2).g(3).h(4): 4483354192
mock(5): 4483368976
mock(6).f(7): 4483708880

观察:

输出显示,在模拟上指定的链式函数调用总是在程序的生存期内返回相同的对象,不管我们调用了多少次。

例如,对mock.f().g().h()的第一次调用,对mock.f().g().h()的第二次调用,甚至第三次具有不同参数的mock.f(2).g(3).h(4)调用都返回完全相同的对象。

问题:

  • 我们能依靠这种行为吗?是否保证在程序的生存期内,mock.f().g().h()会返回完全相同的模拟对象?
  • 是否保证即使相同的具有不同参数的调用链(例如,mock.f(2).g(3).h(4) )也会返回与mock.f().g().h()相同的对象
  • 这两件事都有记载吗?

背景:

我问这个问题的原因是,与其编写这样的代码,不如:

代码语言:javascript
运行
复制
from urllib import request
from unittest.mock import Mock, patch

with patch('urllib.request.urlopen') as mock_urlopen:
    mock_urlopen.return_value = Mock()
    mock_urlopen().getcode.return_value = 200
    assert request.urlopen('').getcode() == 200

我可以编写这样的代码:

代码语言:javascript
运行
复制
from urllib import request
from unittest.mock import Mock, patch

with patch('urllib.request.urlopen') as mock_urlopen:
    mock_urlopen().getcode.return_value = 200
    assert request.urlopen('').getcode() == 200

上面的例子太简单了,只是为了演示。我想保留一些完整的例子。但是如果我能够依赖这个特性,当函数调用链很长时,就会变得非常方便。这就是为什么我正在寻找某种类型的参考或文档,以表明我可以依赖于这种行为。

EN

回答 1

Stack Overflow用户

发布于 2019-08-24 13:14:02

如果您查看文件lib/python3.7/unittest/mock.py

代码语言:javascript
运行
复制
def __getattr__(self, name):
    if name in {'_mock_methods', '_mock_unsafe'}:
        raise AttributeError(name)
    elif self._mock_methods is not None:
        if name not in self._mock_methods or name in _all_magics:
            raise AttributeError("Mock object has no attribute %r" % name)
    elif _is_magic(name):
        raise AttributeError(name)
    if not self._mock_unsafe:
        if name.startswith(('assert', 'assret')):
            raise AttributeError(name)

    result = self._mock_children.get(name)
    if result is _deleted:
        raise AttributeError(name)
    elif result is None:
        wraps = None
        if self._mock_wraps is not None:
            # XXXX should we get the attribute without triggering code
            # execution?
            wraps = getattr(self._mock_wraps, name)

        result = self._get_child_mock(
            parent=self, name=name, wraps=wraps, _new_name=name,
            _new_parent=self
        )
        self._mock_children[name]  = result

    elif isinstance(result, _SpecState):
        result = create_autospec(
            result.spec, result.spec_set, result.instance,
            result.parent, result.name
        )
        self._mock_children[name]  = result

    return result

如您所见,对象被缓存在_mock_children dict中。因此,每个调用都会返回对象。但数据将被更新。通过运行下面的代码,您可以看到

代码语言:javascript
运行
复制
from unittest.mock import Mock

mock = Mock()

mock.a(10)
mock.a.assert_called_with(10)
mock.a(2)
mock.a.assert_called_with(10)

和结果

代码语言:javascript
运行
复制
Traceback (most recent call last):
  File ".../workbench.py", line 8, in <module>
    mock.a.assert_called_with(10)
  File ....lib/python3.7/unittest/mock.py", line 834, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: Expected call: a(10)
Actual call: a(2)

因此,是的,对象将是相同的,但是对象将具有更新的值。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57575929

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档