Skip to content

Commit a8bd0b1

Browse files
authored
Honour resetall() arguments for non-callable mocks (#606)
reset_mock() is defined on NonCallableMock, but resetall() narrowed the kwargs-capable set to (Mock, AsyncMock). NonCallableMagicMock -- what mocker.create_autospec(cls, instance=True) returns -- is not a Mock subclass, so return_value= and side_effect= were silently dropped for it. The guard exists because autospecced functions carry a no-argument reset_mock closure (issue #237); those are plain functions, so they still take the else branch. AsyncMock was redundant: it already subclasses Mock. Co-authored-by: Dylan Pulver <dylanpulver@users.noreply.github.com>
1 parent 6559fdf commit a8bd0b1

3 files changed

Lines changed: 19 additions & 7 deletions

File tree

‎CHANGELOG.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Releases
44
Unreleased
55
----------
66

7+
* `#606 <https://github.com/pytest-dev/pytest-mock/pull/606>`_: ``mocker.resetall(return_value=True, side_effect=True)`` now also applies to non-callable mocks, such as those returned by ``mocker.create_autospec(SomeClass, instance=True)``. Previously both arguments were silently ignored for them.
78
* `#547 <https://github.com/pytest-dev/pytest-mock/issues/547>`_: Added ``SpyType`` for annotating ``mocker.spy`` results.
89
* Dropped support for EOL Python 3.9.
910
* `#147 <https://github.com/pytest-dev/pytest-mock/issues/147>`_: Removed handling of ``RuntimeError: stop called on unstarted patcher``, which can no longer occur in the supported Python versions.

‎src/pytest_mock/plugin.py‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,6 @@ def resetall(
130130
:param bool return_value: Reset the return_value of mocks.
131131
:param bool side_effect: Reset the side_effect of mocks.
132132
"""
133-
supports_reset_mock_with_args: tuple[type[Any], ...]
134-
if hasattr(self, "AsyncMock"):
135-
supports_reset_mock_with_args = (self.Mock, self.AsyncMock)
136-
else:
137-
supports_reset_mock_with_args = (self.Mock,)
138-
139133
for mock_item in self._mock_cache:
140134
# See issue #237.
141135
if not hasattr(mock_item.mock, "reset_mock"):
@@ -145,7 +139,11 @@ def resetall(
145139
mock_item.mock.spy_return_list = []
146140
if hasattr(mock_item.mock, "spy_return_iter"):
147141
mock_item.mock.spy_return_iter = None
148-
if isinstance(mock_item.mock, supports_reset_mock_with_args):
142+
# ``reset_mock`` is defined on ``NonCallableMock``, which is the base
143+
# of every mock class. Autospecced *functions* are plain functions
144+
# carrying a no-argument ``reset_mock`` closure, so they take the
145+
# ``else`` branch.
146+
if isinstance(mock_item.mock, self.NonCallableMock):
149147
mock_item.mock.reset_mock(
150148
return_value=return_value, side_effect=side_effect
151149
)

‎tests/test_pytest_mock.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,19 @@ def test_mocker_resetall(mocker: MockerFixture) -> None:
224224
assert mocked_object.run.return_value != "mocked"
225225

226226

227+
def test_mocker_resetall_non_callable_mock(mocker: MockerFixture) -> None:
228+
"""``resetall`` must honour its arguments for non-callable mocks too (#389)."""
229+
mocked_object = mocker.create_autospec(TestObject, instance=True)
230+
assert not isinstance(mocked_object, mocker.Mock)
231+
mocked_object.run.return_value = "mocked"
232+
mocked_object.run.side_effect = ValueError
233+
234+
mocker.resetall(return_value=True, side_effect=True)
235+
236+
assert mocked_object.run.return_value != "mocked"
237+
assert mocked_object.run.side_effect is None
238+
239+
227240
class TestMockerStub:
228241
def test_call(self, mocker: MockerFixture) -> None:
229242
stub = mocker.stub()

0 commit comments

Comments
 (0)