Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Lib/unittest/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import pprint
import sys
import builtins
from types import ModuleType
from types import ModuleType, MethodType
from functools import wraps, partial


Expand Down Expand Up @@ -121,6 +121,8 @@ def _copy_func_details(func, funcopy):
def _callable(obj):
if isinstance(obj, type):
return True
if isinstance(obj, (staticmethod, classmethod, MethodType)):
return _callable(obj.__func__)
if getattr(obj, '__call__', None) is not None:
return True
return False
Expand Down
40 changes: 39 additions & 1 deletion Lib/unittest/test/testmock/testhelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from unittest.mock import (
call, _Call, create_autospec, MagicMock,
Mock, ANY, _CallList, patch, PropertyMock
Mock, ANY, _CallList, patch, PropertyMock, _callable
)

from datetime import datetime
Expand Down Expand Up @@ -1002,5 +1002,43 @@ def test_propertymock_returnvalue(self):
self.assertNotIsInstance(returned, PropertyMock)


class TestCallablePredicate(unittest.TestCase):

def test_type(self):
for obj in [str, bytes, int, list, tuple, SomeClass]:
self.assertTrue(_callable(obj))

def test_call_magic_method(self):
class Callable:
def __call__(self):
pass
instance = Callable()
self.assertTrue(_callable(instance))

def test_staticmethod(self):
class WithStaticMethod:
@staticmethod
def staticfunc():
pass
self.assertTrue(_callable(WithStaticMethod.staticfunc))

def test_non_callable_staticmethod(self):
class BadStaticMethod:
not_callable = staticmethod(None)
self.assertFalse(_callable(BadStaticMethod.not_callable))

def test_classmethod(self):
class WithClassMethod:
@classmethod
def classfunc(cls):
pass
self.assertTrue(_callable(WithClassMethod.classfunc))

def test_non_callable_classmethod(self):
class BadClassMethod:
not_callable = classmethod(None)
self.assertFalse(_callable(BadClassMethod.not_callable))


if __name__ == '__main__':
unittest.main()
17 changes: 17 additions & 0 deletions Lib/unittest/test/testmock/testmock.py
Original file line number Diff line number Diff line change
Expand Up @@ -1404,6 +1404,23 @@ def test_create_autospec_with_name(self):
m = mock.create_autospec(object(), name='sweet_func')
self.assertIn('sweet_func', repr(m))

#Issue23078
def test_create_autospec_classmethod_and_staticmethod(self):
class TestClass:
@classmethod
def class_method(cls):
pass

@staticmethod
def static_method():
pass
for method in ('class_method', 'static_method'):
with self.subTest(method=method):
mock_method = mock.create_autospec(getattr(TestClass, method))
mock_method()
mock_method.assert_called_once_with()
self.assertRaises(TypeError, mock_method, 'extra_arg')

#Issue21238
def test_mock_unsafe(self):
m = Mock()
Expand Down
20 changes: 20 additions & 0 deletions Lib/unittest/test/testmock/testpatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ def g(self):
pass
foo = 'bar'

@staticmethod
def static_method():
return 24

@classmethod
def class_method(cls):
return 42

class Bar(object):
def a(self):
pass
Expand Down Expand Up @@ -1015,6 +1023,18 @@ def test(mock_function):
self.assertEqual(result, 3)


def test_autospec_staticmethod(self):
with patch('%s.Foo.static_method' % __name__, autospec=True) as method:
Foo.static_method()
method.assert_called_once_with()


def test_autospec_classmethod(self):
with patch('%s.Foo.class_method' % __name__, autospec=True) as method:
Foo.class_method()
method.assert_called_once_with()


def test_autospec_with_new(self):
patcher = patch('%s.function' % __name__, new=3, autospec=True)
self.assertRaises(TypeError, patcher.start)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add support for :func:`classmethod` and :func:`staticmethod` to
:func:`unittest.mock.create_autospec`. Initial patch by Felipe Ochoa.