Add skip_on_error decorator

Change-Id: I1e3b7614313ae24d4c399f71a66098e0a363a29d
This commit is contained in:
Federico Ressi 2021-12-28 08:53:14 +01:00
parent 534329600d
commit f14ad2a1b7
3 changed files with 81 additions and 6 deletions

View File

@ -124,6 +124,7 @@ MultipleObjectsFound = _select.MultipleObjectsFound
SkipException = _skip.SkipException
skip_if = _skip.skip_if
skip_on_error = _skip.skip_on_error
skip_test = _skip.skip_test
skip_unless = _skip.skip_unless
skip = _skip.skip

View File

@ -30,6 +30,10 @@ SkipTarget = typing.Union[typing.Callable,
SkipDecorator = typing.Callable[[SkipTarget], SkipTarget]
SkipOnErrorType = typing.Union[typing.Type[Exception],
typing.Tuple[typing.Type[Exception], ...]]
def skip_test(reason: str,
cause: Exception = None,
bugzilla: int = None) -> typing.NoReturn:
@ -37,7 +41,7 @@ def skip_test(reason: str,
if bugzilla is not None:
reason += f'\nhttps://bugzilla.redhat.com/show_bug.cgi?id={bugzilla}\n'
if cause is not None:
reason += f"\n\n{cause}\n"
reason += f"\n{cause}\n"
raise SkipException(reason) from cause
@ -75,12 +79,31 @@ def skip_unless(reason: str,
predicate=predicate)
def skip_on_error(reason: str,
predicate: typing.Callable,
*args,
error_type: SkipOnErrorType = None,
bugzilla: int = None,
**kwargs) -> \
SkipDecorator:
predicate = _get_skip_predicate(predicate, *args, **kwargs)
return _skip_decorator(reason=reason,
error_type=error_type,
bugzilla=bugzilla,
predicate=predicate)
def _skip_decorator(reason: str,
unless: bool = True,
unless: bool = None,
error_type: SkipOnErrorType = None,
bugzilla: int = None,
predicate: typing.Callable = None) \
-> SkipDecorator:
"""Mark test case for being skipped for a given reason unless it matches"""
if error_type is None:
error_type = tuple()
def decorator(obj: SkipTarget) -> SkipTarget:
method = _get_skip_method(obj)
@ -89,11 +112,18 @@ def _skip_decorator(reason: str,
_reason = reason
cause: typing.Optional[Exception] = None
if predicate is not None:
return_value = predicate()
if unless is bool(return_value):
return method(*args, **kwargs)
return_value: typing.Any = None
try:
return_value = predicate()
except error_type as ex:
cause = ex
else:
if unless in [None, bool(return_value)]:
return method(*args, **kwargs)
if '{return_value' in reason:
_reason = reason.format(return_value=return_value)
if '{cause' in reason:
_reason = reason.format(cause=cause)
skip_test(reason=_reason, cause=cause, bugzilla=bugzilla)
if obj is method:

View File

@ -14,11 +14,13 @@
# under the License.
from __future__ import absolute_import
import typing
import tobiko
from tobiko.tests import unit
def condition(value):
def condition(value: typing.Any):
return value
@ -224,3 +226,45 @@ class NegativeSkipUnlessConditionCalledWithKwargsTest(NegativeSkipBase):
def test_fail(self):
self.test_method_called = True
def raise_an_error(error: Exception):
raise error
def raise_any_error():
pass
@tobiko.skip_on_error('error raised: {cause}',
raise_an_error,
error_type=ValueError,
error=ValueError("It is all right"))
class PositiveSkipOnErrorTest(unit.TobikoUnitTest):
def test_skip_on_error(self):
self.fail('Not skipped')
class PositiveSkipOnErrorMethodTest(unit.TobikoUnitTest):
@tobiko.skip_on_error('error raised: {cause}',
raise_an_error,
error_type=RuntimeError,
error=RuntimeError("It is all right"))
def test_skip_on_error(self):
self.fail('Not skipped')
@tobiko.skip_on_error('error not raised', raise_any_error,
error_type=ValueError)
class NegativeSkipOnErrorTest(NegativeSkipBase):
def test_skip_on_error(self):
self.test_method_called = True
class NegativeSkipOnErrorMethodTest(NegativeSkipBase):
@tobiko.skip_on_error('error not raised', raise_any_error,
error_type=ValueError)
def test_skip_on_error(self):
self.test_method_called = True