MagicMock 的 reset_mock 没有正确重置子模拟的 side_effect
MagicMock's reset_mock not properly resetting sub-mock's side_effect
我在 class 上有一个长期存在的补丁,其创建的实例经历了多批断言。请参阅下面的代码片段了解该场景。
它暴露了 MagicMock.reset_mock
中的(我认为很烦人的)行为,它似乎在子 MagicMock
:
中创建了一个新的 MagicMock
from unittest.mock import MagicMock
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
# Batch 1 of usage: uses side_effect
assert instance.method() == 5
mock_cls.reset_mock(return_value=True, side_effect=True)
# After this, mock_cls.return_value.method has a new id
# Batch 2 of usage: uses return_value
instance.return_value.method.return_value = 6
assert instance.method() == 6 # StopIteration
当 运行 与 Python 3.10.2 时,它会引发一个 StopIteration
:
Traceback (most recent call last):
File "/path/to/code/play/quick_play.py", line 9, in <module>
assert instance.method() == 6
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1104, in __call__
return self._mock_call(*args, **kwargs)
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1108, in _mock_call
return self._execute_mock_call(*args, **kwargs)
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1165, in _execute_mock_call
result = next(effect)
StopIteration
是否可以在不创建新的 MagicMock
的情况下使用 reset_mock
?
或者,我如何手动重置 side_effect
以便片段 运行s?
一边
reset_mock
签名中的 visited=None
参数是什么意思?它在 3.10 docs 和此处
中未记录
def reset_mock(self, visited=None,*, return_value=False, side_effect=False):
有时在生活中,您会回答自己的问题。
替代reset_mock
来自side_effect
docs
If the function returns DEFAULT
then the mock will return its normal value (from the return_value
).
from unittest.mock import MagicMock, DEFAULT
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
instance.method()
# Works, aligns with docs
mock_cls.return_value.method.side_effect = lambda: DEFAULT
instance.method() # <MagicMock name='mock().method()' ...>
# Alternately, this works too
mock_cls.return_value.method.side_effect = None
instance.method() # <MagicMock name='mock().method()' ...>
你也可以找到这个 and 。
修复我的代码段
这里有两个学习点:
- 放弃
reset_mock
转而设置 side_effect = None
return_value
第二批使用错误
- 或者,我可以在
instance
上调用 reset_mock
from unittest.mock import MagicMock
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
# Batch 1 of usage: uses side_effect
assert instance.method() == 5
mock_cls.return_value.method.side_effect = None
# instance.reset_mock(side_effect=True) # Also works
# Batch 2 of usage: uses return_value
instance.method.return_value = 6 # Correct
# instance.return_value.method.return_value = 6 # Original incorrect
assert instance.method() == 6
未来的读者:保持饥饿,保持愚蠢。
我在 class 上有一个长期存在的补丁,其创建的实例经历了多批断言。请参阅下面的代码片段了解该场景。
它暴露了 MagicMock.reset_mock
中的(我认为很烦人的)行为,它似乎在子 MagicMock
:
MagicMock
from unittest.mock import MagicMock
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
# Batch 1 of usage: uses side_effect
assert instance.method() == 5
mock_cls.reset_mock(return_value=True, side_effect=True)
# After this, mock_cls.return_value.method has a new id
# Batch 2 of usage: uses return_value
instance.return_value.method.return_value = 6
assert instance.method() == 6 # StopIteration
当 运行 与 Python 3.10.2 时,它会引发一个 StopIteration
:
Traceback (most recent call last):
File "/path/to/code/play/quick_play.py", line 9, in <module>
assert instance.method() == 6
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1104, in __call__
return self._mock_call(*args, **kwargs)
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1108, in _mock_call
return self._execute_mock_call(*args, **kwargs)
File "/path/to/.pyenv/versions/3.10.2/lib/python3.10/unittest/mock.py", line 1165, in _execute_mock_call
result = next(effect)
StopIteration
是否可以在不创建新的 MagicMock
的情况下使用 reset_mock
?
或者,我如何手动重置 side_effect
以便片段 运行s?
一边
reset_mock
签名中的 visited=None
参数是什么意思?它在 3.10 docs 和此处
def reset_mock(self, visited=None,*, return_value=False, side_effect=False):
有时在生活中,您会回答自己的问题。
替代reset_mock
来自side_effect
docs
If the function returns
DEFAULT
then the mock will return its normal value (from thereturn_value
).
from unittest.mock import MagicMock, DEFAULT
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
instance.method()
# Works, aligns with docs
mock_cls.return_value.method.side_effect = lambda: DEFAULT
instance.method() # <MagicMock name='mock().method()' ...>
# Alternately, this works too
mock_cls.return_value.method.side_effect = None
instance.method() # <MagicMock name='mock().method()' ...>
你也可以找到这个
修复我的代码段
这里有两个学习点:
- 放弃
reset_mock
转而设置side_effect = None
return_value
第二批使用错误- 或者,我可以在
instance
上调用
reset_mock
from unittest.mock import MagicMock
mock_cls = MagicMock()
mock_cls.return_value.method.side_effect = [5]
instance = mock_cls()
# Batch 1 of usage: uses side_effect
assert instance.method() == 5
mock_cls.return_value.method.side_effect = None
# instance.reset_mock(side_effect=True) # Also works
# Batch 2 of usage: uses return_value
instance.method.return_value = 6 # Correct
# instance.return_value.method.return_value = 6 # Original incorrect
assert instance.method() == 6
未来的读者:保持饥饿,保持愚蠢。