This commit is contained in:
ton
2024-10-07 10:13:40 +07:00
parent aa1631742f
commit 3a7d696db6
9729 changed files with 1832837 additions and 161742 deletions

View File

@@ -84,9 +84,13 @@ class TestLoader(object):
raise TypeError("Test cases should not be derived from "
"TestSuite. Maybe you meant to derive from "
"TestCase?")
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
if testCaseClass in (case.TestCase, case.FunctionTestCase):
# We don't load any tests from base types that should not be loaded.
testCaseNames = []
else:
testCaseNames = self.getTestCaseNames(testCaseClass)
if not testCaseNames and hasattr(testCaseClass, 'runTest'):
testCaseNames = ['runTest']
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
return loaded_suite
@@ -95,7 +99,11 @@ class TestLoader(object):
tests = []
for name in dir(module):
obj = getattr(module, name)
if isinstance(obj, type) and issubclass(obj, case.TestCase):
if (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
tests.append(self.loadTestsFromTestCase(obj))
load_tests = getattr(module, 'load_tests', None)
@@ -164,7 +172,11 @@ class TestLoader(object):
if isinstance(obj, types.ModuleType):
return self.loadTestsFromModule(obj)
elif isinstance(obj, type) and issubclass(obj, case.TestCase):
elif (
isinstance(obj, type)
and issubclass(obj, case.TestCase)
and obj not in (case.TestCase, case.FunctionTestCase)
):
return self.loadTestsFromTestCase(obj)
elif (isinstance(obj, types.FunctionType) and
isinstance(parent, type) and
@@ -242,6 +254,7 @@ class TestLoader(object):
Paths are sorted before being imported to ensure reproducible execution
order even on filesystems with non-alphabetical ordering like ext3/4.
"""
original_top_level_dir = self._top_level_dir
set_implicit_top = False
if top_level_dir is None and self._top_level_dir is not None:
# make top_level_dir optional if called from load_tests in a package
@@ -295,6 +308,7 @@ class TestLoader(object):
raise ImportError('Start directory is not importable: %r' % start_dir)
tests = list(self._find_tests(start_dir, pattern))
self._top_level_dir = original_top_level_dir
return self.suiteClass(tests)
def _get_directory_containing_module(self, module_name):

View File

@@ -280,7 +280,7 @@ class TestProgram(object):
testRunner = self.testRunner
self.result = testRunner.run(self.test)
if self.exit:
if self.result.testsRun == 0:
if self.result.testsRun == 0 and len(self.result.skipped) == 0:
sys.exit(_NO_TESTS_EXITCODE)
elif self.result.wasSuccessful():
sys.exit(0)

View File

@@ -543,7 +543,7 @@ class NonCallableMock(Base):
if self._mock_delegate is not None:
ret = self._mock_delegate.return_value
if ret is DEFAULT:
if ret is DEFAULT and self._mock_wraps is None:
ret = self._get_child_mock(
_new_parent=self, _new_name='()'
)
@@ -598,7 +598,9 @@ class NonCallableMock(Base):
side_effect = property(__get_side_effect, __set_side_effect)
def reset_mock(self, visited=None,*, return_value=False, side_effect=False):
def reset_mock(self, visited=None, *,
return_value: bool = False,
side_effect: bool = False):
"Restore the mock object to its initial state."
if visited is None:
visited = []
@@ -800,6 +802,9 @@ class NonCallableMock(Base):
mock_name = f'{self._extract_mock_name()}.{name}'
raise AttributeError(f'Cannot set {mock_name}')
if isinstance(value, PropertyMock):
self.__dict__[name] = value
return
return object.__setattr__(self, name, value)
@@ -827,7 +832,7 @@ class NonCallableMock(Base):
def _format_mock_failure_message(self, args, kwargs, action='call'):
message = 'expected %s not found.\nExpected: %s\nActual: %s'
message = 'expected %s not found.\nExpected: %s\n Actual: %s'
expected_string = self._format_mock_call_signature(args, kwargs)
call_args = self.call_args
actual_string = self._format_mock_call_signature(*call_args)
@@ -930,7 +935,7 @@ class NonCallableMock(Base):
if self.call_args is None:
expected = self._format_mock_call_signature(args, kwargs)
actual = 'not called.'
error_message = ('expected call not found.\nExpected: %s\nActual: %s'
error_message = ('expected call not found.\nExpected: %s\n Actual: %s'
% (expected, actual))
raise AssertionError(error_message)
@@ -981,7 +986,7 @@ class NonCallableMock(Base):
raise AssertionError(
f'{problem}\n'
f'Expected: {_CallList(calls)}'
f'{self._calls_repr(prefix="Actual").rstrip(".")}'
f'{self._calls_repr(prefix=" Actual").rstrip(".")}'
) from cause
return
@@ -1204,6 +1209,9 @@ class CallableMixin(Base):
if self._mock_return_value is not DEFAULT:
return self.return_value
if self._mock_delegate and self._mock_delegate.return_value is not DEFAULT:
return self.return_value
if self._mock_wraps is not None:
return self._mock_wraps(*args, **kwargs)
@@ -1475,13 +1483,12 @@ class _patch(object):
if isinstance(original, type):
# If we're patching out a class and there is a spec
inherit = True
if spec is None and _is_async_obj(original):
Klass = AsyncMock
else:
Klass = MagicMock
_kwargs = {}
# Determine the Klass to use
if new_callable is not None:
Klass = new_callable
elif spec is None and _is_async_obj(original):
Klass = AsyncMock
elif spec is not None or spec_set is not None:
this_spec = spec
if spec_set is not None:
@@ -1494,7 +1501,12 @@ class _patch(object):
Klass = AsyncMock
elif not_callable:
Klass = NonCallableMagicMock
else:
Klass = MagicMock
else:
Klass = MagicMock
_kwargs = {}
if spec is not None:
_kwargs['spec'] = spec
if spec_set is not None:
@@ -2179,6 +2191,17 @@ class MagicMock(MagicMixin, Mock):
self._mock_add_spec(spec, spec_set)
self._mock_set_magics()
def reset_mock(self, /, *args, return_value: bool = False, **kwargs):
if (
return_value
and self._mock_name
and _is_magic(self._mock_name)
):
# Don't reset return values for magic methods,
# otherwise `m.__str__` will start
# to return `MagicMock` instances, instead of `str` instances.
return_value = False
super().reset_mock(*args, return_value=return_value, **kwargs)
class MagicProxy(Base):
@@ -2199,8 +2222,11 @@ class MagicProxy(Base):
return self.create_mock()
_CODE_ATTRS = dir(CodeType)
_CODE_SIG = inspect.signature(partial(CodeType.__init__, None))
try:
_CODE_SIG = inspect.signature(partial(CodeType.__init__, None))
_CODE_ATTRS = dir(CodeType)
except ValueError:
_CODE_SIG = None
class AsyncMockMixin(Base):
@@ -2220,9 +2246,12 @@ class AsyncMockMixin(Base):
self.__dict__['_mock_await_count'] = 0
self.__dict__['_mock_await_args'] = None
self.__dict__['_mock_await_args_list'] = _CallList()
code_mock = NonCallableMock(spec_set=_CODE_ATTRS)
code_mock.__dict__["_spec_class"] = CodeType
code_mock.__dict__["_spec_signature"] = _CODE_SIG
if _CODE_SIG:
code_mock = NonCallableMock(spec_set=_CODE_ATTRS)
code_mock.__dict__["_spec_class"] = CodeType
code_mock.__dict__["_spec_signature"] = _CODE_SIG
else:
code_mock = NonCallableMock(spec_set=CodeType)
code_mock.co_flags = (
inspect.CO_COROUTINE
+ inspect.CO_VARARGS
@@ -2709,6 +2738,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
if not unsafe:
_check_spec_arg_typos(kwargs)
_name = kwargs.pop('name', _name)
_new_name = _name
if _parent is None:
# for a top level object no _new_name should be set
_new_name = ''
_kwargs.update(kwargs)
Klass = MagicMock
@@ -2726,13 +2761,6 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
elif is_type and instance and not _instance_callable(spec):
Klass = NonCallableMagicMock
_name = _kwargs.pop('name', _name)
_new_name = _name
if _parent is None:
# for a top level object no _new_name should be set
_new_name = ''
mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
name=_name, **_kwargs)
@@ -2748,9 +2776,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
if _parent is not None and not instance:
_parent._mock_children[_name] = mock
# Pop wraps from kwargs because it must not be passed to configure_mock.
wrapped = kwargs.pop('wraps', None)
if is_type and not instance and 'return_value' not in kwargs:
mock.return_value = create_autospec(spec, spec_set, instance=True,
_name='()', _parent=mock)
_name='()', _parent=mock,
wraps=wrapped)
for entry in dir(spec):
if _is_magic(entry):
@@ -2771,9 +2802,12 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
except AttributeError:
continue
kwargs = {'spec': original}
child_kwargs = {'spec': original}
# Wrap child attributes also.
if wrapped and hasattr(wrapped, entry):
child_kwargs.update(wraps=original)
if spec_set:
kwargs = {'spec_set': original}
child_kwargs = {'spec_set': original}
if not isinstance(original, FunctionTypes):
new = _SpecState(original, spec_set, mock, entry, instance)
@@ -2784,14 +2818,13 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
parent = mock.mock
skipfirst = _must_skip(spec, entry, is_type)
kwargs['_eat_self'] = skipfirst
child_kwargs['_eat_self'] = skipfirst
if iscoroutinefunction(original):
child_klass = AsyncMock
else:
child_klass = MagicMock
new = child_klass(parent=parent, name=entry, _new_name=entry,
_new_parent=parent,
**kwargs)
_new_parent=parent, **child_kwargs)
mock._mock_children[entry] = new
new.return_value = child_klass()
_check_signature(original, new, skipfirst=skipfirst)
@@ -2802,6 +2835,11 @@ def create_autospec(spec, spec_set=False, instance=False, _parent=None,
# setting as an instance attribute?
if isinstance(new, FunctionTypes):
setattr(mock, entry, new)
# kwargs are passed with respect to the parent mock so, they are not used
# for creating return_value of the parent mock. So, this condition
# should be true only for the parent mock if kwargs are given.
if _is_instance_mock(mock) and kwargs:
mock.configure_mock(**kwargs)
return mock

View File

@@ -274,7 +274,7 @@ class TextTestRunner(object):
infos.append("failures=%d" % failed)
if errored:
infos.append("errors=%d" % errored)
elif run == 0:
elif run == 0 and not skipped:
self.stream.write("NO TESTS RAN")
else:
self.stream.write("OK")