Browse Source

Fixed #18551 -- Enabled skipIfDBFeature/skipUnlessDBFeature to decorate a class

Thanks Tim Graham for the review and improved patch.
Claude Paroz 11 years ago
parent
commit
6d52844b9b
3 changed files with 48 additions and 6 deletions
  1. 12 1
      django/test/testcases.py
  2. 11 2
      docs/topics/testing/overview.txt
  3. 25 3
      tests/test_utils/tests.py

+ 12 - 1
django/test/testcases.py

@@ -879,10 +879,19 @@ class TestCase(TransactionTestCase):
             self.atomics[db_name].__exit__(None, None, None)
 
 
+class CheckCondition(object):
+    """Descriptor class for deferred condition checking"""
+    def __init__(self, cond_func):
+        self.cond_func = cond_func
+
+    def __get__(self, obj, objtype):
+        return self.cond_func()
+
+
 def _deferredSkip(condition, reason):
     def decorator(test_func):
         if not (isinstance(test_func, type) and
-                issubclass(test_func, TestCase)):
+                issubclass(test_func, unittest.TestCase)):
             @wraps(test_func)
             def skip_wrapper(*args, **kwargs):
                 if condition():
@@ -890,7 +899,9 @@ def _deferredSkip(condition, reason):
                 return test_func(*args, **kwargs)
             test_item = skip_wrapper
         else:
+            # Assume a class is decorated
             test_item = test_func
+            test_item.__unittest_skip__ = CheckCondition(condition)
         test_item.__unittest_skip_why__ = reason
         return test_item
     return decorator

+ 11 - 2
docs/topics/testing/overview.txt

@@ -1804,7 +1804,8 @@ for skipping tests.
 
 .. function:: skipIfDBFeature(feature_name_string)
 
-Skip the decorated test if the named database feature is supported.
+Skip the decorated test or ``TestCase`` if the named database feature is
+supported.
 
 For example, the following test will not be executed if the database
 supports transactions (e.g., it would *not* run under PostgreSQL, but
@@ -1815,9 +1816,13 @@ it would under MySQL with MyISAM tables)::
         def test_transaction_behavior(self):
             # ... conditional test code
 
+.. versionchanged:: 1.7
+
+    ``skipIfDBFeature`` can now be used to decorate a ``TestCase`` class.
+
 .. function:: skipUnlessDBFeature(feature_name_string)
 
-Skip the decorated test if the named database feature is *not*
+Skip the decorated test or ``TestCase`` if the named database feature is *not*
 supported.
 
 For example, the following test will only be executed if the database
@@ -1828,3 +1833,7 @@ under MySQL with MyISAM tables)::
         @skipUnlessDBFeature('supports_transactions')
         def test_transaction_behavior(self):
             # ... conditional test code
+
+.. versionchanged:: 1.7
+
+    ``skipUnlessDBFeature`` can now be used to decorate a ``TestCase`` class.

+ 25 - 3
tests/test_utils/tests.py

@@ -2,13 +2,12 @@
 from __future__ import absolute_import, unicode_literals
 
 import unittest
-from unittest import skip
 
 from django.db import connection
 from django.forms import EmailField, IntegerField
 from django.http import HttpResponse
 from django.template.loader import render_to_string
-from django.test import SimpleTestCase, TestCase, skipUnlessDBFeature
+from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
 from django.test.html import HTMLParseError, parse_html
 from django.test.utils import CaptureQueriesContext, IgnoreAllDeprecationWarningsMixin
 from django.utils import six
@@ -27,6 +26,29 @@ class SkippingTestCase(TestCase):
         self.assertRaises(ValueError, test_func)
 
 
+class SkippingClassTestCase(TestCase):
+    def test_skip_class_unless_db_feature(self):
+        @skipUnlessDBFeature("__class__")
+        class NotSkippedTests(unittest.TestCase):
+            def test_dummy(self):
+                return
+
+        @skipIfDBFeature("__class__")
+        class SkippedTests(unittest.TestCase):
+            def test_will_be_skipped(self):
+                self.fail("We should never arrive here.")
+
+        test_suite = unittest.TestSuite()
+        test_suite.addTest(NotSkippedTests('test_dummy'))
+        try:
+            test_suite.addTest(SkippedTests('test_will_be_skipped'))
+        except unittest.SkipTest:
+            self.fail("SkipTest should not be raised at this stage")
+        result = unittest.TextTestRunner(stream=six.StringIO()).run(test_suite)
+        self.assertEqual(result.testsRun, 2)
+        self.assertEqual(len(result.skipped), 1)
+
+
 class AssertNumQueriesTests(TestCase):
     urls = 'test_utils.urls'
 
@@ -561,7 +583,7 @@ class SkippingExtraTests(TestCase):
         with self.assertNumQueries(0):
             super(SkippingExtraTests, self).__call__(result)
 
-    @skip("Fixture loading should not be performed for skipped tests.")
+    @unittest.skip("Fixture loading should not be performed for skipped tests.")
     def test_fixtures_are_skipped(self):
         pass