Skip to content

Commit 15a57a3

Browse files
authored
bpo-23078: Add support for {class,static}method to mock.create_autospec() (GH-11613)
Co-authored-by: Felipe <felipe.nospam.ochoa@gmail.com> (cherry picked from commit 9b21856)
1 parent 71b8882 commit 15a57a3

5 files changed

Lines changed: 81 additions & 2 deletions

File tree

Lib/unittest/mock.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import pprint
3030
import sys
3131
import builtins
32-
from types import ModuleType
32+
from types import ModuleType, MethodType
3333
from functools import wraps, partial
3434

3535

@@ -121,6 +121,8 @@ def _copy_func_details(func, funcopy):
121121
def _callable(obj):
122122
if isinstance(obj, type):
123123
return True
124+
if isinstance(obj, (staticmethod, classmethod, MethodType)):
125+
return _callable(obj.__func__)
124126
if getattr(obj, '__call__', None) is not None:
125127
return True
126128
return False

Lib/unittest/test/testmock/testhelpers.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from unittest.mock import (
77
call, _Call, create_autospec, MagicMock,
8-
Mock, ANY, _CallList, patch, PropertyMock
8+
Mock, ANY, _CallList, patch, PropertyMock, _callable
99
)
1010

1111
from datetime import datetime
@@ -1002,5 +1002,43 @@ def test_propertymock_returnvalue(self):
10021002
self.assertNotIsInstance(returned, PropertyMock)
10031003

10041004

1005+
class TestCallablePredicate(unittest.TestCase):
1006+
1007+
def test_type(self):
1008+
for obj in [str, bytes, int, list, tuple, SomeClass]:
1009+
self.assertTrue(_callable(obj))
1010+
1011+
def test_call_magic_method(self):
1012+
class Callable:
1013+
def __call__(self):
1014+
pass
1015+
instance = Callable()
1016+
self.assertTrue(_callable(instance))
1017+
1018+
def test_staticmethod(self):
1019+
class WithStaticMethod:
1020+
@staticmethod
1021+
def staticfunc():
1022+
pass
1023+
self.assertTrue(_callable(WithStaticMethod.staticfunc))
1024+
1025+
def test_non_callable_staticmethod(self):
1026+
class BadStaticMethod:
1027+
not_callable = staticmethod(None)
1028+
self.assertFalse(_callable(BadStaticMethod.not_callable))
1029+
1030+
def test_classmethod(self):
1031+
class WithClassMethod:
1032+
@classmethod
1033+
def classfunc(cls):
1034+
pass
1035+
self.assertTrue(_callable(WithClassMethod.classfunc))
1036+
1037+
def test_non_callable_classmethod(self):
1038+
class BadClassMethod:
1039+
not_callable = classmethod(None)
1040+
self.assertFalse(_callable(BadClassMethod.not_callable))
1041+
1042+
10051043
if __name__ == '__main__':
10061044
unittest.main()

Lib/unittest/test/testmock/testmock.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,23 @@ def test_create_autospec_with_name(self):
14041404
m = mock.create_autospec(object(), name='sweet_func')
14051405
self.assertIn('sweet_func', repr(m))
14061406

1407+
#Issue23078
1408+
def test_create_autospec_classmethod_and_staticmethod(self):
1409+
class TestClass:
1410+
@classmethod
1411+
def class_method(cls):
1412+
pass
1413+
1414+
@staticmethod
1415+
def static_method():
1416+
pass
1417+
for method in ('class_method', 'static_method'):
1418+
with self.subTest(method=method):
1419+
mock_method = mock.create_autospec(getattr(TestClass, method))
1420+
mock_method()
1421+
mock_method.assert_called_once_with()
1422+
self.assertRaises(TypeError, mock_method, 'extra_arg')
1423+
14071424
#Issue21238
14081425
def test_mock_unsafe(self):
14091426
m = Mock()

Lib/unittest/test/testmock/testpatch.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,14 @@ def g(self):
5151
pass
5252
foo = 'bar'
5353

54+
@staticmethod
55+
def static_method():
56+
return 24
57+
58+
@classmethod
59+
def class_method(cls):
60+
return 42
61+
5462
class Bar(object):
5563
def a(self):
5664
pass
@@ -1015,6 +1023,18 @@ def test(mock_function):
10151023
self.assertEqual(result, 3)
10161024

10171025

1026+
def test_autospec_staticmethod(self):
1027+
with patch('%s.Foo.static_method' % __name__, autospec=True) as method:
1028+
Foo.static_method()
1029+
method.assert_called_once_with()
1030+
1031+
1032+
def test_autospec_classmethod(self):
1033+
with patch('%s.Foo.class_method' % __name__, autospec=True) as method:
1034+
Foo.class_method()
1035+
method.assert_called_once_with()
1036+
1037+
10181038
def test_autospec_with_new(self):
10191039
patcher = patch('%s.function' % __name__, new=3, autospec=True)
10201040
self.assertRaises(TypeError, patcher.start)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Add support for :func:`classmethod` and :func:`staticmethod` to
2+
:func:`unittest.mock.create_autospec`. Initial patch by Felipe Ochoa.

0 commit comments

Comments
 (0)