]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-113569: Display calls in Mock.assert_has_calls failure when empty (GH-113573)
authorwookie184 <wookie1840@gmail.com>
Thu, 4 Jan 2024 19:11:34 +0000 (19:11 +0000)
committerGitHub <noreply@github.com>
Thu, 4 Jan 2024 19:11:34 +0000 (21:11 +0200)
Lib/test/test_unittest/testmock/testmock.py
Lib/unittest/mock.py
Misc/NEWS.d/next/Library/2023-12-29-17-57-45.gh-issue-113569.qcRCEI.rst [new file with mode: 0644]

index 6af8acc3b0617ebb7a494e3d88cf09daebd4c281..1725406bcfb9e41af757fae8e448e5b2e105deff 100644 (file)
@@ -1547,25 +1547,33 @@ class MockTest(unittest.TestCase):
         mock = Mock(spec=f)
         mock(1)
 
-        with self.assertRaisesRegex(
-                AssertionError,
-                '^{}$'.format(
-                    re.escape('Calls not found.\n'
-                              'Expected: [call()]\n'
-                              '  Actual: [call(1)]'))) as cm:
+        with self.assertRaises(AssertionError) as cm:
             mock.assert_has_calls([call()])
+        self.assertEqual(str(cm.exception),
+            'Calls not found.\n'
+            'Expected: [call()]\n'
+            '  Actual: [call(1)]'
+        )
         self.assertIsNone(cm.exception.__cause__)
 
+        uncalled_mock = Mock()
+        with self.assertRaises(AssertionError) as cm:
+            uncalled_mock.assert_has_calls([call()])
+        self.assertEqual(str(cm.exception),
+            'Calls not found.\n'
+            'Expected: [call()]\n'
+            '  Actual: []'
+        )
+        self.assertIsNone(cm.exception.__cause__)
 
-        with self.assertRaisesRegex(
-                AssertionError,
-                '^{}$'.format(
-                    re.escape(
-                        'Error processing expected calls.\n'
-                        "Errors: [None, TypeError('too many positional arguments')]\n"
-                        "Expected: [call(), call(1, 2)]\n"
-                        '  Actual: [call(1)]'))) as cm:
+        with self.assertRaises(AssertionError) as cm:
             mock.assert_has_calls([call(), call(1, 2)])
+        self.assertEqual(str(cm.exception),
+            'Error processing expected calls.\n'
+            "Errors: [None, TypeError('too many positional arguments')]\n"
+            'Expected: [call(), call(1, 2)]\n'
+            '  Actual: [call(1)]'
+        )
         self.assertIsInstance(cm.exception.__cause__, TypeError)
 
     def test_assert_any_call(self):
index 2adb3d70662b1a10a88b5de54694c67837ff4dee..93f4d9743ed2fa94b5d08ee980ea1d074fbe3be8 100644 (file)
@@ -1010,8 +1010,8 @@ class NonCallableMock(Base):
                                     for e in expected])
                 raise AssertionError(
                     f'{problem}\n'
-                    f'Expected: {_CallList(calls)}'
-                    f'{self._calls_repr(prefix="  Actual").rstrip(".")}'
+                    f'Expected: {_CallList(calls)}\n'
+                    f'  Actual: {safe_repr(self.mock_calls)}'
                 ) from cause
             return
 
@@ -1085,7 +1085,7 @@ class NonCallableMock(Base):
         return klass(**kw)
 
 
-    def _calls_repr(self, prefix="Calls"):
+    def _calls_repr(self):
         """Renders self.mock_calls as a string.
 
         Example: "\nCalls: [call(1), call(2)]."
@@ -1095,7 +1095,7 @@ class NonCallableMock(Base):
         """
         if not self.mock_calls:
             return ""
-        return f"\n{prefix}: {safe_repr(self.mock_calls)}."
+        return f"\nCalls: {safe_repr(self.mock_calls)}."
 
 
 # Denylist for forbidden attribute names in safe mode
diff --git a/Misc/NEWS.d/next/Library/2023-12-29-17-57-45.gh-issue-113569.qcRCEI.rst b/Misc/NEWS.d/next/Library/2023-12-29-17-57-45.gh-issue-113569.qcRCEI.rst
new file mode 100644 (file)
index 0000000..9b63fc9
--- /dev/null
@@ -0,0 +1,2 @@
+Indicate if there were no actual calls in unittest
+:meth:`~unittest.mock.Mock.assert_has_calls` failure.