Fixed #27214 -- Made skip db features decorators respect wrapping order and inheritance.
This commit is contained in:
parent
0627858ada
commit
18c72d59e0
|
@ -1083,11 +1083,23 @@ class TestCase(TransactionTestCase):
|
||||||
|
|
||||||
class CheckCondition(object):
|
class CheckCondition(object):
|
||||||
"""Descriptor class for deferred condition checking"""
|
"""Descriptor class for deferred condition checking"""
|
||||||
def __init__(self, cond_func):
|
def __init__(self, *conditions):
|
||||||
self.cond_func = cond_func
|
self.conditions = conditions
|
||||||
|
|
||||||
|
def add_condition(self, condition, reason):
|
||||||
|
return self.__class__(*self.conditions + ((condition, reason),))
|
||||||
|
|
||||||
def __get__(self, instance, cls=None):
|
def __get__(self, instance, cls=None):
|
||||||
return self.cond_func()
|
# Trigger access for all bases.
|
||||||
|
if any(getattr(base, '__unittest_skip__', False) for base in cls.__bases__):
|
||||||
|
return True
|
||||||
|
for condition, reason in self.conditions:
|
||||||
|
if condition():
|
||||||
|
# Override this descriptor's value and set the skip reason.
|
||||||
|
cls.__unittest_skip__ = True
|
||||||
|
cls.__unittest_skip_why__ = reason
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def _deferredSkip(condition, reason):
|
def _deferredSkip(condition, reason):
|
||||||
|
@ -1103,8 +1115,13 @@ def _deferredSkip(condition, reason):
|
||||||
else:
|
else:
|
||||||
# Assume a class is decorated
|
# Assume a class is decorated
|
||||||
test_item = test_func
|
test_item = test_func
|
||||||
test_item.__unittest_skip__ = CheckCondition(condition)
|
# Retrieve the possibly existing value from the class's dict to
|
||||||
test_item.__unittest_skip_why__ = reason
|
# avoid triggering the descriptor.
|
||||||
|
skip = test_func.__dict__.get('__unittest_skip__')
|
||||||
|
if isinstance(skip, CheckCondition):
|
||||||
|
test_item.__unittest_skip__ = skip.add_condition(condition, reason)
|
||||||
|
elif skip is not True:
|
||||||
|
test_item.__unittest_skip__ = CheckCondition((condition, reason))
|
||||||
return test_item
|
return test_item
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
|
@ -106,20 +106,28 @@ class SkippingClassTestCase(SimpleTestCase):
|
||||||
def test_dummy(self):
|
def test_dummy(self):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@skipUnlessDBFeature("missing")
|
||||||
@skipIfDBFeature("__class__")
|
@skipIfDBFeature("__class__")
|
||||||
class SkippedTests(unittest.TestCase):
|
class SkippedTests(unittest.TestCase):
|
||||||
def test_will_be_skipped(self):
|
def test_will_be_skipped(self):
|
||||||
self.fail("We should never arrive here.")
|
self.fail("We should never arrive here.")
|
||||||
|
|
||||||
|
@skipIfDBFeature("__dict__")
|
||||||
|
class SkippedTestsSubclass(SkippedTests):
|
||||||
|
pass
|
||||||
|
|
||||||
test_suite = unittest.TestSuite()
|
test_suite = unittest.TestSuite()
|
||||||
test_suite.addTest(NotSkippedTests('test_dummy'))
|
test_suite.addTest(NotSkippedTests('test_dummy'))
|
||||||
try:
|
try:
|
||||||
test_suite.addTest(SkippedTests('test_will_be_skipped'))
|
test_suite.addTest(SkippedTests('test_will_be_skipped'))
|
||||||
|
test_suite.addTest(SkippedTestsSubclass('test_will_be_skipped'))
|
||||||
except unittest.SkipTest:
|
except unittest.SkipTest:
|
||||||
self.fail("SkipTest should not be raised at this stage")
|
self.fail("SkipTest should not be raised at this stage")
|
||||||
result = unittest.TextTestRunner(stream=six.StringIO()).run(test_suite)
|
result = unittest.TextTestRunner(stream=six.StringIO()).run(test_suite)
|
||||||
self.assertEqual(result.testsRun, 2)
|
self.assertEqual(result.testsRun, 3)
|
||||||
self.assertEqual(len(result.skipped), 1)
|
self.assertEqual(len(result.skipped), 2)
|
||||||
|
self.assertEqual(result.skipped[0][1], 'Database has feature(s) __class__')
|
||||||
|
self.assertEqual(result.skipped[1][1], 'Database has feature(s) __class__')
|
||||||
|
|
||||||
|
|
||||||
@override_settings(ROOT_URLCONF='test_utils.urls')
|
@override_settings(ROOT_URLCONF='test_utils.urls')
|
||||||
|
|
Loading…
Reference in New Issue