Clarify and fix assertions that mocks have not been awaited (GH-18196)
- The gc.collect is needed for other implementations, such as pypy - Using context managers over multiple lines will only catch the warning from the first line in the context! - remove a skip for a test that no longer fails on pypy
This commit is contained in:
parent
c7dd3c7d87
commit
a46575a8f2
|
@ -1,7 +1,9 @@
|
|||
import asyncio
|
||||
import gc
|
||||
import inspect
|
||||
import re
|
||||
import unittest
|
||||
from contextlib import contextmanager
|
||||
|
||||
from asyncio import run, iscoroutinefunction
|
||||
from unittest import IsolatedAsyncioTestCase
|
||||
|
@ -52,6 +54,15 @@ async_foo_name = f'{__name__}.AsyncClass'
|
|||
normal_foo_name = f'{__name__}.NormalClass'
|
||||
|
||||
|
||||
@contextmanager
|
||||
def assertNeverAwaited(test):
|
||||
with test.assertWarnsRegex(RuntimeWarning, "was never awaited$"):
|
||||
yield
|
||||
# In non-CPython implementations of Python, this is needed because timely
|
||||
# deallocation is not guaranteed by the garbage collector.
|
||||
gc.collect()
|
||||
|
||||
|
||||
class AsyncPatchDecoratorTest(unittest.TestCase):
|
||||
def test_is_coroutine_function_patch(self):
|
||||
@patch.object(AsyncClass, 'async_method')
|
||||
|
@ -284,8 +295,7 @@ class AsyncSpecTest(unittest.TestCase):
|
|||
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
|
||||
with assertNeverAwaited(self):
|
||||
self.assertTrue(inspect.isawaitable(async_mock()))
|
||||
|
||||
sync_mock = mock_type(spec=normal_func)
|
||||
|
@ -299,8 +309,7 @@ class AsyncSpecTest(unittest.TestCase):
|
|||
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
|
||||
with assertNeverAwaited(self):
|
||||
self.assertTrue(inspect.isawaitable(async_mock()))
|
||||
|
||||
sync_mock = mock_type(normal_func)
|
||||
|
@ -747,8 +756,7 @@ class AsyncMockAssert(unittest.TestCase):
|
|||
|
||||
def test_assert_called_but_not_awaited(self):
|
||||
mock = AsyncMock(AsyncClass)
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
mock.async_method()
|
||||
self.assertTrue(iscoroutinefunction(mock.async_method))
|
||||
mock.async_method.assert_called()
|
||||
|
@ -789,9 +797,9 @@ class AsyncMockAssert(unittest.TestCase):
|
|||
def test_assert_called_twice_and_awaited_once(self):
|
||||
mock = AsyncMock(AsyncClass)
|
||||
coroutine = mock.async_method()
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# The first call will be awaited so no warning there
|
||||
# But this call will never get awaited, so it will warn here
|
||||
# The first call will be awaited so no warning there
|
||||
# But this call will never get awaited, so it will warn here
|
||||
with assertNeverAwaited(self):
|
||||
mock.async_method()
|
||||
with self.assertRaises(AssertionError):
|
||||
mock.async_method.assert_awaited()
|
||||
|
@ -826,38 +834,34 @@ class AsyncMockAssert(unittest.TestCase):
|
|||
|
||||
def test_assert_has_calls_not_awaits(self):
|
||||
kalls = [call('foo')]
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
self.mock('foo')
|
||||
self.mock.assert_has_calls(kalls)
|
||||
with self.assertRaises(AssertionError):
|
||||
self.mock.assert_has_awaits(kalls)
|
||||
|
||||
def test_assert_has_mock_calls_on_async_mock_no_spec(self):
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
self.mock()
|
||||
kalls_empty = [('', (), {})]
|
||||
self.assertEqual(self.mock.mock_calls, kalls_empty)
|
||||
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
self.mock('foo')
|
||||
with assertNeverAwaited(self):
|
||||
self.mock('baz')
|
||||
mock_kalls = ([call(), call('foo'), call('baz')])
|
||||
self.assertEqual(self.mock.mock_calls, mock_kalls)
|
||||
|
||||
def test_assert_has_mock_calls_on_async_mock_with_spec(self):
|
||||
a_class_mock = AsyncMock(AsyncClass)
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
a_class_mock.async_method()
|
||||
kalls_empty = [('', (), {})]
|
||||
self.assertEqual(a_class_mock.async_method.mock_calls, kalls_empty)
|
||||
self.assertEqual(a_class_mock.mock_calls, [call.async_method()])
|
||||
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise a warning because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
a_class_mock.async_method(1, 2, 3, a=4, b=5)
|
||||
method_kalls = [call(), call(1, 2, 3, a=4, b=5)]
|
||||
mock_kalls = [call.async_method(), call.async_method(1, 2, 3, a=4, b=5)]
|
||||
|
@ -865,9 +869,9 @@ class AsyncMockAssert(unittest.TestCase):
|
|||
self.assertEqual(a_class_mock.mock_calls, mock_kalls)
|
||||
|
||||
def test_async_method_calls_recorded(self):
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise warnings because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
self.mock.something(3, fish=None)
|
||||
with assertNeverAwaited(self):
|
||||
self.mock.something_else.something(6, cake=sentinel.Cake)
|
||||
|
||||
self.assertEqual(self.mock.method_calls, [
|
||||
|
@ -889,19 +893,20 @@ class AsyncMockAssert(unittest.TestCase):
|
|||
self.assertEqual(attr, [])
|
||||
|
||||
assert_attrs(self.mock)
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise warnings because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
self.mock()
|
||||
with assertNeverAwaited(self):
|
||||
self.mock(1, 2)
|
||||
with assertNeverAwaited(self):
|
||||
self.mock(a=3)
|
||||
|
||||
self.mock.reset_mock()
|
||||
assert_attrs(self.mock)
|
||||
|
||||
a_mock = AsyncMock(AsyncClass)
|
||||
with self.assertWarns(RuntimeWarning):
|
||||
# Will raise warnings because never awaited
|
||||
with assertNeverAwaited(self):
|
||||
a_mock.async_method()
|
||||
with assertNeverAwaited(self):
|
||||
a_mock.async_method(1, a=3)
|
||||
|
||||
a_mock.reset_mock()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import math
|
||||
import unittest
|
||||
import os
|
||||
import sys
|
||||
from asyncio import iscoroutinefunction
|
||||
from unittest.mock import AsyncMock, Mock, MagicMock, _magics
|
||||
|
||||
|
@ -429,7 +428,6 @@ class TestMockingMagicMethods(unittest.TestCase):
|
|||
self.assertEqual(dir(mock), ['foo'])
|
||||
|
||||
|
||||
@unittest.skipIf('PyPy' in sys.version, "This fails differently on pypy")
|
||||
def test_bound_methods(self):
|
||||
m = Mock()
|
||||
|
||||
|
|
Loading…
Reference in New Issue