Skip to content

Commit

Permalink
bpo-38163: Child mocks detect their type as sync or async (GH-16471)
Browse files Browse the repository at this point in the history
Backports: 3667e1ee6c90e6d3b6a745cd590ece87118f81ad
Signed-off-by: Chris Withers <chris@withers.org>
  • Loading branch information
lisroach authored and cjw296 committed Jan 22, 2020
1 parent e51fbb6 commit aed690d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 27 deletions.
4 changes: 4 additions & 0 deletions NEWS.d/2019-09-28-20-16-40.bpo-38163.x51-vK.rst
@@ -0,0 +1,4 @@
Child mocks will now detect their type as either synchronous or
asynchronous, asynchronous child mocks will be AsyncMocks and synchronous
child mocks will be either MagicMock or Mock (depending on their parent
type).
5 changes: 3 additions & 2 deletions mock/mock.py
Expand Up @@ -999,8 +999,9 @@ def _get_child_mock(self, **kw):
# Any asynchronous magic becomes an AsyncMock
klass = AsyncMock
elif issubclass(_type, AsyncMockMixin):
if _new_name in _all_sync_magics:
# Any synchronous magic becomes a MagicMock
if (_new_name in _all_sync_magics or
self._mock_methods and _new_name in self._mock_methods):
# Any synchronous method on AsyncMock becomes a MagicMock
klass = MagicMock
else:
klass = AsyncMock
Expand Down
67 changes: 42 additions & 25 deletions mock/tests/testasync.py
Expand Up @@ -4,7 +4,7 @@
import re
import unittest

from mock import (ANY, call, AsyncMock, patch, MagicMock,
from mock import (ANY, call, AsyncMock, patch, MagicMock, Mock,
create_autospec, sentinel)
from mock.mock import _CallList

Expand Down Expand Up @@ -246,33 +246,50 @@ async def test_async():


class AsyncSpecTest(unittest.TestCase):
def test_spec_as_async_positional_magicmock(self):
mock = MagicMock(async_func)
self.assertIsInstance(mock, MagicMock)
m = mock()
self.assertTrue(inspect.isawaitable(m))
run(m)
def test_spec_normal_methods_on_class(self):
def inner_test(mock_type):
mock = mock_type(AsyncClass)
self.assertIsInstance(mock.async_method, AsyncMock)
self.assertIsInstance(mock.normal_method, MagicMock)

def test_spec_as_async_kw_magicmock(self):
mock = MagicMock(spec=async_func)
self.assertIsInstance(mock, MagicMock)
m = mock()
self.assertTrue(inspect.isawaitable(m))
run(m)
for mock_type in [AsyncMock, MagicMock]:
with self.subTest(f"test method types with {mock_type}"):
inner_test(mock_type)

def test_spec_as_async_kw_AsyncMock(self):
mock = AsyncMock(spec=async_func)
self.assertIsInstance(mock, AsyncMock)
m = mock()
self.assertTrue(inspect.isawaitable(m))
run(m)
def test_spec_normal_methods_on_class_with_mock(self):
mock = Mock(AsyncClass)
self.assertIsInstance(mock.async_method, AsyncMock)
self.assertIsInstance(mock.normal_method, Mock)

def test_spec_as_async_positional_AsyncMock(self):
mock = AsyncMock(async_func)
self.assertIsInstance(mock, AsyncMock)
m = mock()
self.assertTrue(inspect.isawaitable(m))
run(m)
def test_spec_mock_type_kw(self):
def inner_test(mock_type):
async_mock = mock_type(spec=async_func)
self.assertIsInstance(async_mock, mock_type)
with self.assertWarns(RuntimeWarning):
# Will raise a warning because never awaited
self.assertTrue(inspect.isawaitable(async_mock()))

sync_mock = mock_type(spec=normal_func)
self.assertIsInstance(sync_mock, mock_type)

for mock_type in [AsyncMock, MagicMock, Mock]:
with self.subTest(f"test spec kwarg with {mock_type}"):
inner_test(mock_type)

def test_spec_mock_type_positional(self):
def inner_test(mock_type):
async_mock = mock_type(async_func)
self.assertIsInstance(async_mock, mock_type)
with self.assertWarns(RuntimeWarning):
# Will raise a warning because never awaited
self.assertTrue(inspect.isawaitable(async_mock()))

sync_mock = mock_type(normal_func)
self.assertIsInstance(sync_mock, mock_type)

for mock_type in [AsyncMock, MagicMock, Mock]:
with self.subTest(f"test spec positional with {mock_type}"):
inner_test(mock_type)

def test_spec_as_normal_kw_AsyncMock(self):
mock = AsyncMock(spec=normal_func)
Expand Down

0 comments on commit aed690d

Please sign in to comment.