From 5675eb371f8af55569602c2c6c6f275968b1ce3b Mon Sep 17 00:00:00 2001 From: Claude Paroz Date: Sat, 23 Aug 2014 18:01:33 +0200 Subject: [PATCH] Allowed skipIf/UnlessDBFeature to accept several feature strings --- django/test/testcases.py | 20 +++++++----- docs/topics/testing/tools.txt | 20 ++++++++---- tests/test_utils/tests.py | 61 +++++++++++++++++++++++++++++++++-- 3 files changed, 85 insertions(+), 16 deletions(-) diff --git a/django/test/testcases.py b/django/test/testcases.py index 260d7c8af7..a4edf4929a 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -976,20 +976,24 @@ def _deferredSkip(condition, reason): return decorator -def skipIfDBFeature(feature): +def skipIfDBFeature(*features): """ - Skip a test if a database has the named feature + Skip a test if a database has at least one of the named features. """ - return _deferredSkip(lambda: getattr(connection.features, feature, False), - "Database has feature %s" % feature) + return _deferredSkip( + lambda: any(getattr(connection.features, feature, False) for feature in features), + "Database has feature(s) %s" % ", ".join(features) + ) -def skipUnlessDBFeature(feature): +def skipUnlessDBFeature(*features): """ - Skip a test unless a database has the named feature + Skip a test unless a database has all the named features. """ - return _deferredSkip(lambda: not getattr(connection.features, feature, False), - "Database doesn't support feature %s" % feature) + return _deferredSkip( + lambda: not all(getattr(connection.features, feature, False) for feature in features), + "Database doesn't support feature(s): %s" % ", ".join(features) + ) class QuietWSGIRequestHandler(WSGIRequestHandler): diff --git a/docs/topics/testing/tools.txt b/docs/topics/testing/tools.txt index 7519fb9e63..70cbbdabfe 100644 --- a/docs/topics/testing/tools.txt +++ b/docs/topics/testing/tools.txt @@ -1610,10 +1610,10 @@ features class. See ``django.db.backends.BaseDatabaseFeatures`` class for a full list of database features that can be used as a basis for skipping tests. -.. function:: skipIfDBFeature(feature_name_string) +.. function:: skipIfDBFeature(*feature_name_strings) -Skip the decorated test or ``TestCase`` if the named database feature is -supported. +Skip the decorated test or ``TestCase`` if all of the named database features +are supported. For example, the following test will not be executed if the database supports transactions (e.g., it would *not* run under PostgreSQL, but @@ -1628,10 +1628,14 @@ it would under MySQL with MyISAM tables):: ``skipIfDBFeature`` can now be used to decorate a ``TestCase`` class. -.. function:: skipUnlessDBFeature(feature_name_string) +.. versionchanged:: 1.8 -Skip the decorated test or ``TestCase`` if the named database feature is *not* -supported. + ``skipIfDBFeature`` can accept multiple feature strings. + +.. function:: skipUnlessDBFeature(*feature_name_strings) + +Skip the decorated test or ``TestCase`` if any of the named database features +are *not* supported. For example, the following test will only be executed if the database supports transactions (e.g., it would run under PostgreSQL, but *not* @@ -1645,3 +1649,7 @@ under MySQL with MyISAM tables):: .. versionchanged:: 1.7 ``skipUnlessDBFeature`` can now be used to decorate a ``TestCase`` class. + +.. versionchanged:: 1.8 + + ``skipUnlessDBFeature`` can accept multiple feature strings. diff --git a/tests/test_utils/tests.py b/tests/test_utils/tests.py index b2e4207fa5..8cd0019f7b 100644 --- a/tests/test_utils/tests.py +++ b/tests/test_utils/tests.py @@ -19,14 +19,71 @@ from .views import empty_response class SkippingTestCase(TestCase): + def _assert_skipping(self, func, expected_exc): + # We cannot simply use assertRaises because a SkipTest exception will go unnoticed + try: + func() + except expected_exc: + pass + except Exception as e: + self.fail("No %s exception should have been raised for %s." % ( + e.__class__.__name__, func.__name__)) + def test_skip_unless_db_feature(self): - "A test that might be skipped is actually called." + """ + Testing the django.test.skipUnlessDBFeature decorator. + """ # Total hack, but it works, just want an attribute that's always true. @skipUnlessDBFeature("__class__") def test_func(): raise ValueError - self.assertRaises(ValueError, test_func) + @skipUnlessDBFeature("notprovided") + def test_func2(): + raise ValueError + + @skipUnlessDBFeature("__class__", "__class__") + def test_func3(): + raise ValueError + + @skipUnlessDBFeature("__class__", "notprovided") + def test_func4(): + raise ValueError + + self._assert_skipping(test_func, ValueError) + self._assert_skipping(test_func2, unittest.SkipTest) + self._assert_skipping(test_func3, ValueError) + self._assert_skipping(test_func4, unittest.SkipTest) + + def test_skip_if_db_feature(self): + """ + Testing the django.test.skipIfDBFeature decorator. + """ + @skipIfDBFeature("__class__") + def test_func(): + raise ValueError + + @skipIfDBFeature("notprovided") + def test_func2(): + raise ValueError + + @skipIfDBFeature("__class__", "__class__") + def test_func3(): + raise ValueError + + @skipIfDBFeature("__class__", "notprovided") + def test_func4(): + raise ValueError + + @skipIfDBFeature("notprovided", "notprovided") + def test_func5(): + raise ValueError + + self._assert_skipping(test_func, unittest.SkipTest) + self._assert_skipping(test_func2, ValueError) + self._assert_skipping(test_func3, unittest.SkipTest) + self._assert_skipping(test_func4, unittest.SkipTest) + self._assert_skipping(test_func5, ValueError) class SkippingClassTestCase(TestCase):