Lon*_*ner 1 python unit-testing monkeypatching mocking
Code:
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()
Run Code Online (Sandbox Code Playgroud)
Output:
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
Run Code Online (Sandbox Code Playgroud)
Observation:
The output shows that a specified chained function call on a mock always returns the same object within the lifetime of a program regardless of how many times we make that call.
For example, the first call to mock.f().g().h(), the second call to mock.f().g().h(), and even the third call with different arguments mock.f(2).g(3).h(4) return the exact same object.
Question:
mock.f().g().h() would return the exact same mock object?mock.f(2).g(3).h(4) would also return the same object as a mock.f().g().h()?Background:
The reason why I am asking this is so that instead of writing code like this:
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
Run Code Online (Sandbox Code Playgroud)
I can write code like this insted:
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
Run Code Online (Sandbox Code Playgroud)
The examples above are too simple only for demo purpose. I wanted to keep self-contained examples. But if I could rely on this feature, it would become very convenient when the chain of function calls are long. That's why I am looking for some sort of reference or documentation that shows that I can rely on this behavior.
如果你看文件 lib/python3.7/unittest/mock.py
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
Run Code Online (Sandbox Code Playgroud)
如您所见,对象在_mock_childrendict中缓存。因此,每次调用都会返回该对象。但是数据将被更新。通过运行以下代码可以看到
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)
Run Code Online (Sandbox Code Playgroud)
和结果
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)
Run Code Online (Sandbox Code Playgroud)
因此,是的,对象将是相同的,但是对象将具有更新后的值
| 归档时间: |
|
| 查看次数: |
94 次 |
| 最近记录: |