]> granicus.if.org Git - python/commitdiff
bpo-35047, unittest.mock: Better error messages on assert_called_xxx failures (GH...
authorPetter Strandmark <petter.strandmark@gmail.com>
Sun, 28 Oct 2018 20:37:10 +0000 (21:37 +0100)
committerVictor Stinner <vstinner@redhat.com>
Sun, 28 Oct 2018 20:37:10 +0000 (21:37 +0100)
unittest.mock now includes mock calls in exception messages if
assert_not_called, assert_called_once, or assert_called_once_with
fails.

Lib/unittest/mock.py
Lib/unittest/test/testmock/testmock.py
Misc/ACKS
Misc/NEWS.d/next/Library/2018-10-25-09-59-00.bpo-35047.abbaa.rst [new file with mode: 0644]

index 1a6c1a606c5a257211e460033d8e0cb38a50f37b..1977b870834b7b150dc2bedc0984ef20e2274a31 100644 (file)
@@ -30,6 +30,7 @@ import pprint
 import sys
 import builtins
 from types import ModuleType
+from unittest.util import safe_repr
 from functools import wraps, partial
 
 
@@ -778,8 +779,10 @@ class NonCallableMock(Base):
         """
         self = _mock_self
         if self.call_count != 0:
-            msg = ("Expected '%s' to not have been called. Called %s times." %
-                   (self._mock_name or 'mock', self.call_count))
+            msg = ("Expected '%s' to not have been called. Called %s times.%s"
+                   % (self._mock_name or 'mock',
+                      self.call_count,
+                      self._calls_repr()))
             raise AssertionError(msg)
 
     def assert_called(_mock_self):
@@ -796,8 +799,10 @@ class NonCallableMock(Base):
         """
         self = _mock_self
         if not self.call_count == 1:
-            msg = ("Expected '%s' to have been called once. Called %s times." %
-                   (self._mock_name or 'mock', self.call_count))
+            msg = ("Expected '%s' to have been called once. Called %s times.%s"
+                   % (self._mock_name or 'mock',
+                      self.call_count,
+                      self._calls_repr()))
             raise AssertionError(msg)
 
     def assert_called_with(_mock_self, *args, **kwargs):
@@ -825,8 +830,10 @@ class NonCallableMock(Base):
         with the specified arguments."""
         self = _mock_self
         if not self.call_count == 1:
-            msg = ("Expected '%s' to be called once. Called %s times." %
-                   (self._mock_name or 'mock', self.call_count))
+            msg = ("Expected '%s' to be called once. Called %s times.%s"
+                   % (self._mock_name or 'mock',
+                      self.call_count,
+                      self._calls_repr()))
             raise AssertionError(msg)
         return self.assert_called_with(*args, **kwargs)
 
@@ -847,8 +854,8 @@ class NonCallableMock(Base):
         if not any_order:
             if expected not in all_calls:
                 raise AssertionError(
-                    'Calls not found.\nExpected: %r\n'
-                    'Actual: %r' % (_CallList(calls), self.mock_calls)
+                    'Calls not found.\nExpected: %r%s'
+                    % (_CallList(calls), self._calls_repr(prefix="Actual"))
                 ) from cause
             return
 
@@ -909,6 +916,19 @@ class NonCallableMock(Base):
         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):
     if obj is None:
index c7bfa277b511ca96aae59072f146b0bb79b528ef..8cd284a6522d6135890660626636ea7748b61aca 100644 (file)
@@ -1,4 +1,5 @@
 import copy
+import re
 import sys
 import tempfile
 
@@ -407,6 +408,14 @@ class MockTest(unittest.TestCase):
             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 f(a, b, c, d=None):
@@ -1250,6 +1259,13 @@ class MockTest(unittest.TestCase):
         with self.assertRaises(AssertionError):
             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):
         m = Mock()
         with self.assertRaises(AssertionError):
@@ -1271,6 +1287,20 @@ class MockTest(unittest.TestCase):
         with self.assertRaises(AssertionError):
             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
     def test_sorted_call_signature(self):
         m = Mock()
index 5014584b7bc0b73d0a22f062f7eb034be85580d2..043d604a3f96a183b1d697f60176194f339b4457 100644 (file)
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1570,6 +1570,7 @@ Daniel Stokes
 Michael Stone
 Serhiy Storchaka
 Ken Stox
+Petter Strandmark
 Charalampos Stratakis
 Dan Stromberg
 Donald Stufft
diff --git a/Misc/NEWS.d/next/Library/2018-10-25-09-59-00.bpo-35047.abbaa.rst b/Misc/NEWS.d/next/Library/2018-10-25-09-59-00.bpo-35047.abbaa.rst
new file mode 100644 (file)
index 0000000..12eda27
--- /dev/null
@@ -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.
\ No newline at end of file