mirror of
https://github.com/python/cpython.git
synced 2025-09-26 18:29:57 +00:00
bpo-35047, unittest.mock: Better error messages on assert_called_xxx failures (GH-10090)
unittest.mock now includes mock calls in exception messages if assert_not_called, assert_called_once, or assert_called_once_with fails.
This commit is contained in:
parent
18032632ab
commit
47d94241a3
4 changed files with 62 additions and 8 deletions
|
@ -30,6 +30,7 @@ import pprint
|
||||||
import sys
|
import sys
|
||||||
import builtins
|
import builtins
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
from unittest.util import safe_repr
|
||||||
from functools import wraps, partial
|
from functools import wraps, partial
|
||||||
|
|
||||||
|
|
||||||
|
@ -778,8 +779,10 @@ class NonCallableMock(Base):
|
||||||
"""
|
"""
|
||||||
self = _mock_self
|
self = _mock_self
|
||||||
if self.call_count != 0:
|
if self.call_count != 0:
|
||||||
msg = ("Expected '%s' to not have been called. Called %s times." %
|
msg = ("Expected '%s' to not have been called. Called %s times.%s"
|
||||||
(self._mock_name or 'mock', self.call_count))
|
% (self._mock_name or 'mock',
|
||||||
|
self.call_count,
|
||||||
|
self._calls_repr()))
|
||||||
raise AssertionError(msg)
|
raise AssertionError(msg)
|
||||||
|
|
||||||
def assert_called(_mock_self):
|
def assert_called(_mock_self):
|
||||||
|
@ -796,8 +799,10 @@ class NonCallableMock(Base):
|
||||||
"""
|
"""
|
||||||
self = _mock_self
|
self = _mock_self
|
||||||
if not self.call_count == 1:
|
if not self.call_count == 1:
|
||||||
msg = ("Expected '%s' to have been called once. Called %s times." %
|
msg = ("Expected '%s' to have been called once. Called %s times.%s"
|
||||||
(self._mock_name or 'mock', self.call_count))
|
% (self._mock_name or 'mock',
|
||||||
|
self.call_count,
|
||||||
|
self._calls_repr()))
|
||||||
raise AssertionError(msg)
|
raise AssertionError(msg)
|
||||||
|
|
||||||
def assert_called_with(_mock_self, *args, **kwargs):
|
def assert_called_with(_mock_self, *args, **kwargs):
|
||||||
|
@ -825,8 +830,10 @@ class NonCallableMock(Base):
|
||||||
with the specified arguments."""
|
with the specified arguments."""
|
||||||
self = _mock_self
|
self = _mock_self
|
||||||
if not self.call_count == 1:
|
if not self.call_count == 1:
|
||||||
msg = ("Expected '%s' to be called once. Called %s times." %
|
msg = ("Expected '%s' to be called once. Called %s times.%s"
|
||||||
(self._mock_name or 'mock', self.call_count))
|
% (self._mock_name or 'mock',
|
||||||
|
self.call_count,
|
||||||
|
self._calls_repr()))
|
||||||
raise AssertionError(msg)
|
raise AssertionError(msg)
|
||||||
return self.assert_called_with(*args, **kwargs)
|
return self.assert_called_with(*args, **kwargs)
|
||||||
|
|
||||||
|
@ -847,8 +854,8 @@ class NonCallableMock(Base):
|
||||||
if not any_order:
|
if not any_order:
|
||||||
if expected not in all_calls:
|
if expected not in all_calls:
|
||||||
raise AssertionError(
|
raise AssertionError(
|
||||||
'Calls not found.\nExpected: %r\n'
|
'Calls not found.\nExpected: %r%s'
|
||||||
'Actual: %r' % (_CallList(calls), self.mock_calls)
|
% (_CallList(calls), self._calls_repr(prefix="Actual"))
|
||||||
) from cause
|
) from cause
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -909,6 +916,19 @@ class NonCallableMock(Base):
|
||||||
return klass(**kw)
|
return klass(**kw)
|
||||||
|
|
||||||
|
|
||||||
|
def _calls_repr(self, prefix="Calls"):
|
||||||
|
"""Renders self.mock_calls as a string.
|
||||||
|
|
||||||
|
Example: "\nCalls: [call(1), call(2)]."
|
||||||
|
|
||||||
|
If self.mock_calls is empty, an empty string is returned. The
|
||||||
|
output will be truncated if very long.
|
||||||
|
"""
|
||||||
|
if not self.mock_calls:
|
||||||
|
return ""
|
||||||
|
return f"\n{prefix}: {safe_repr(self.mock_calls)}."
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _try_iter(obj):
|
def _try_iter(obj):
|
||||||
if obj is None:
|
if obj is None:
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import copy
|
import copy
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
@ -407,6 +408,14 @@ class MockTest(unittest.TestCase):
|
||||||
lambda: mock.assert_called_once_with('bob', 'bar', baz=2)
|
lambda: mock.assert_called_once_with('bob', 'bar', baz=2)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_assert_called_once_with_call_list(self):
|
||||||
|
m = Mock()
|
||||||
|
m(1)
|
||||||
|
m(2)
|
||||||
|
self.assertRaisesRegex(AssertionError,
|
||||||
|
re.escape("Calls: [call(1), call(2)]"),
|
||||||
|
lambda: m.assert_called_once_with(2))
|
||||||
|
|
||||||
|
|
||||||
def test_assert_called_once_with_function_spec(self):
|
def test_assert_called_once_with_function_spec(self):
|
||||||
def f(a, b, c, d=None):
|
def f(a, b, c, d=None):
|
||||||
|
@ -1250,6 +1259,13 @@ class MockTest(unittest.TestCase):
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
m.hello.assert_not_called()
|
m.hello.assert_not_called()
|
||||||
|
|
||||||
|
def test_assert_not_called_message(self):
|
||||||
|
m = Mock()
|
||||||
|
m(1, 2)
|
||||||
|
self.assertRaisesRegex(AssertionError,
|
||||||
|
re.escape("Calls: [call(1, 2)]"),
|
||||||
|
m.assert_not_called)
|
||||||
|
|
||||||
def test_assert_called(self):
|
def test_assert_called(self):
|
||||||
m = Mock()
|
m = Mock()
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
|
@ -1271,6 +1287,20 @@ class MockTest(unittest.TestCase):
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
m.hello.assert_called_once()
|
m.hello.assert_called_once()
|
||||||
|
|
||||||
|
def test_assert_called_once_message(self):
|
||||||
|
m = Mock()
|
||||||
|
m(1, 2)
|
||||||
|
m(3)
|
||||||
|
self.assertRaisesRegex(AssertionError,
|
||||||
|
re.escape("Calls: [call(1, 2), call(3)]"),
|
||||||
|
m.assert_called_once)
|
||||||
|
|
||||||
|
def test_assert_called_once_message_not_called(self):
|
||||||
|
m = Mock()
|
||||||
|
with self.assertRaises(AssertionError) as e:
|
||||||
|
m.assert_called_once()
|
||||||
|
self.assertNotIn("Calls:", str(e.exception))
|
||||||
|
|
||||||
#Issue21256 printout of keyword args should be in deterministic order
|
#Issue21256 printout of keyword args should be in deterministic order
|
||||||
def test_sorted_call_signature(self):
|
def test_sorted_call_signature(self):
|
||||||
m = Mock()
|
m = Mock()
|
||||||
|
|
|
@ -1570,6 +1570,7 @@ Daniel Stokes
|
||||||
Michael Stone
|
Michael Stone
|
||||||
Serhiy Storchaka
|
Serhiy Storchaka
|
||||||
Ken Stox
|
Ken Stox
|
||||||
|
Petter Strandmark
|
||||||
Charalampos Stratakis
|
Charalampos Stratakis
|
||||||
Dan Stromberg
|
Dan Stromberg
|
||||||
Donald Stufft
|
Donald Stufft
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
``unittest.mock`` now includes mock calls in exception messages if
|
||||||
|
``assert_not_called``, ``assert_called_once``, or ``assert_called_once_with``
|
||||||
|
fails. Patch by Petter Strandmark.
|
Loading…
Add table
Add a link
Reference in a new issue