bpo-23078: Add support for {class,static}method to mock.create_autospec() (GH-11613)

Co-authored-by: Felipe <felipe.nospam.ochoa@gmail.com>
This commit is contained in:
Xtreak 2019-04-22 08:00:23 +05:30 committed by Berker Peksag
parent 9541bd321a
commit 9b21856b0f
5 changed files with 81 additions and 2 deletions

View File

@ -29,7 +29,7 @@ import inspect
import pprint
import sys
import builtins
from types import ModuleType
from types import ModuleType, MethodType
from unittest.util import safe_repr
from functools import wraps, partial
@ -122,6 +122,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

View File

@ -5,7 +5,7 @@ import unittest
from unittest.mock import (
call, _Call, create_autospec, MagicMock,
Mock, ANY, _CallList, patch, PropertyMock
Mock, ANY, _CallList, patch, PropertyMock, _callable
)
from datetime import datetime
@ -1011,5 +1011,43 @@ class TestCallList(unittest.TestCase):
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()

View File

@ -1419,6 +1419,23 @@ class MockTest(unittest.TestCase):
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()

View File

@ -51,6 +51,14 @@ class Foo(object):
pass
foo = 'bar'
@staticmethod
def static_method():
return 24
@classmethod
def class_method(cls):
return 42
class Bar(object):
def a(self):
pass
@ -1023,6 +1031,18 @@ class PatchTest(unittest.TestCase):
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)

View File

@ -0,0 +1,2 @@
Add support for :func:`classmethod` and :func:`staticmethod` to
:func:`unittest.mock.create_autospec`. Initial patch by Felipe Ochoa.