From 2a71a0d6ab8719defc9309da20bd97b7b35262b6 Mon Sep 17 00:00:00 2001 From: Igor Nikolaev Date: Thu, 19 Oct 2023 17:56:50 +0300 Subject: [PATCH] mocker.resetall now also resets mockers created by `create_autospec` (#390) Fixes #389 --- CHANGELOG.rst | 7 +++++++ src/pytest_mock/plugin.py | 13 +++++++++++-- tests/test_pytest_mock.py | 22 +++++++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index b2fb47f..7617d23 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,13 @@ Releases ======== +3.12.0 (2023-10-19) +------------------- + +* ``mocker.resetall()`` now also resets mocks created by ``mocker.create_autospec`` (`#390`_). + +.. _#390: https://github.com/pytest-dev/pytest-mock/pull/390 + 3.11.1 (2023-06-15) ------------------- diff --git a/src/pytest_mock/plugin.py b/src/pytest_mock/plugin.py index 4e9609a..673f98b 100644 --- a/src/pytest_mock/plugin.py +++ b/src/pytest_mock/plugin.py @@ -66,12 +66,20 @@ def __init__(self, config: Any) -> None: self.call = mock_module.call self.ANY = mock_module.ANY self.DEFAULT = mock_module.DEFAULT - self.create_autospec = mock_module.create_autospec self.sentinel = mock_module.sentinel self.mock_open = mock_module.mock_open if hasattr(mock_module, "seal"): self.seal = mock_module.seal + def create_autospec( + self, spec: Any, spec_set: bool = False, instance: bool = False, **kwargs: Any + ) -> MockType: + m: MockType = self.mock_module.create_autospec( + spec, spec_set, instance, **kwargs + ) + self._patches_and_mocks.append((None, m)) + return m + def resetall( self, *, return_value: bool = False, side_effect: bool = False ) -> None: @@ -102,7 +110,8 @@ def stopall(self) -> None: times. """ for p, m in reversed(self._patches_and_mocks): - p.stop() + if p is not None: + p.stop() self._patches_and_mocks.clear() def stop(self, mock: unittest.mock.MagicMock) -> None: diff --git a/tests/test_pytest_mock.py b/tests/test_pytest_mock.py index 3d53241..fdeed0c 100644 --- a/tests/test_pytest_mock.py +++ b/tests/test_pytest_mock.py @@ -60,6 +60,15 @@ def ls(cls, path): return os.listdir(path) +class TestObject: + """ + Class that is used for testing create_autospec with child mocks + """ + + def run(self) -> str: + return "not mocked" + + @pytest.fixture def check_unix_fs_mocked( tmpdir: Any, mocker: MockerFixture @@ -156,7 +165,6 @@ def test_mock_patch_dict_resetall(mocker: MockerFixture) -> None: [ "ANY", "call", - "create_autospec", "MagicMock", "Mock", "mock_open", @@ -185,23 +193,35 @@ def test_mocker_resetall(mocker: MockerFixture) -> None: listdir = mocker.patch("os.listdir", return_value="foo") open = mocker.patch("os.open", side_effect=["bar", "baz"]) + mocked_object = mocker.create_autospec(TestObject) + mocked_object.run.return_value = "mocked" + assert listdir("/tmp") == "foo" assert open("/tmp/foo.txt") == "bar" + assert mocked_object.run() == "mocked" listdir.assert_called_once_with("/tmp") open.assert_called_once_with("/tmp/foo.txt") + mocked_object.run.assert_called_once() mocker.resetall() assert not listdir.called assert not open.called + assert not mocked_object.called assert listdir.return_value == "foo" assert list(open.side_effect) == ["baz"] + assert mocked_object.run.return_value == "mocked" mocker.resetall(return_value=True, side_effect=True) assert isinstance(listdir.return_value, mocker.Mock) assert open.side_effect is None + if sys.version_info >= (3, 9): + # The reset on child mocks have been implemented in 3.9 + # https://bugs.python.org/issue38932 + assert mocked_object.run.return_value != "mocked" + class TestMockerStub: def test_call(self, mocker: MockerFixture) -> None: