Fixed #14508 - test suite silences warnings.

Utility functions get_warnings_state and save_warnings_state have been added
to django.test.utils, and methods to django.test.TestCase for convenience.

The implementation is based on the catch_warnings context manager from
Python 2.6.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14526 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Luke Plant 2010-11-11 15:06:20 +00:00
parent 7beca4d3e5
commit 02fc6276d7
10 changed files with 87 additions and 25 deletions

View File

@ -154,13 +154,13 @@ class RowlevelBackendTest(TestCase):
self.user1 = User.objects.create_user('test', 'test@example.com', 'test') self.user1 = User.objects.create_user('test', 'test@example.com', 'test')
self.user2 = User.objects.create_user('test2', 'test2@example.com', 'test') self.user2 = User.objects.create_user('test2', 'test2@example.com', 'test')
self.user3 = User.objects.create_user('test3', 'test3@example.com', 'test') self.user3 = User.objects.create_user('test3', 'test3@example.com', 'test')
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth') module='django.contrib.auth')
def tearDown(self): def tearDown(self):
settings.AUTHENTICATION_BACKENDS = self.curr_auth settings.AUTHENTICATION_BACKENDS = self.curr_auth
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)
def test_has_perm(self): def test_has_perm(self):
self.assertEqual(self.user1.has_perm('perm', TestObj()), False) self.assertEqual(self.user1.has_perm('perm', TestObj()), False)

View File

@ -51,6 +51,7 @@ class BaseTest(TestCase):
self._message_storage = settings.MESSAGE_STORAGE self._message_storage = settings.MESSAGE_STORAGE
settings.MESSAGE_STORAGE = '%s.%s' % (self.storage_class.__module__, settings.MESSAGE_STORAGE = '%s.%s' % (self.storage_class.__module__,
self.storage_class.__name__) self.storage_class.__name__)
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth.models') module='django.contrib.auth.models')
@ -63,8 +64,7 @@ class BaseTest(TestCase):
self._template_context_processors self._template_context_processors
settings.INSTALLED_APPS = self._installed_apps settings.INSTALLED_APPS = self._installed_apps
settings.MESSAGE_STORAGE = self._message_storage settings.MESSAGE_STORAGE = self._message_storage
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)
def restore_setting(self, setting): def restore_setting(self, setting):
if setting in self._remembered_settings: if setting in self._remembered_settings:

View File

@ -11,6 +11,7 @@ from django.db import transaction, connection, connections, DEFAULT_DB_ALIAS
from django.http import QueryDict from django.http import QueryDict
from django.test import _doctest as doctest from django.test import _doctest as doctest
from django.test.client import Client from django.test.client import Client
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import simplejson, unittest as ut2 from django.utils import simplejson, unittest as ut2
from django.utils.encoding import smart_str from django.utils.encoding import smart_str
from django.utils.functional import wraps from django.utils.functional import wraps
@ -328,6 +329,19 @@ class TransactionTestCase(ut2.TestCase):
settings.ROOT_URLCONF = self._old_root_urlconf settings.ROOT_URLCONF = self._old_root_urlconf
clear_url_caches() clear_url_caches()
def save_warnings_state(self):
"""
Saves the state of the warnings module
"""
self._warnings_state = get_warnings_state()
def restore_warnings_state(self):
"""
Restores the sate of the warnings module to the state
saved by save_warnings_state()
"""
restore_warnings_state(self._warnings_state)
def assertRedirects(self, response, expected_url, status_code=302, def assertRedirects(self, response, expected_url, status_code=302,
target_status_code=200, host=None, msg_prefix=''): target_status_code=200, host=None, msg_prefix=''):
"""Asserts that a response redirected to a specific URL, and that the """Asserts that a response redirected to a specific URL, and that the

View File

@ -1,6 +1,7 @@
import sys import sys
import time import time
import os import os
import warnings
from django.conf import settings from django.conf import settings
from django.core import mail from django.core import mail
from django.core.mail.backends import locmem from django.core.mail.backends import locmem
@ -46,6 +47,7 @@ class ContextList(list):
return False return False
return True return True
def instrumented_test_render(self, context): def instrumented_test_render(self, context):
""" """
An instrumented Template render method, providing a signal An instrumented Template render method, providing a signal
@ -75,6 +77,7 @@ def setup_test_environment():
deactivate() deactivate()
def teardown_test_environment(): def teardown_test_environment():
"""Perform any global post-test teardown. This involves: """Perform any global post-test teardown. This involves:
@ -93,6 +96,25 @@ def teardown_test_environment():
del mail.outbox del mail.outbox
def get_warnings_state():
"""
Returns an object containing the state of the warnings module
"""
# There is no public interface for doing this, but this implementation of
# get_warnings_state and restore_warnings_state appears to work on Python
# 2.4 to 2.7.
return warnings.filters[:]
def restore_warnings_state(state):
"""
Restores the state of the warnings module when passed an object that was
returned by get_warnings_state()
"""
warnings.filters = state[:]
def get_runner(settings): def get_runner(settings):
test_path = settings.TEST_RUNNER.split('.') test_path = settings.TEST_RUNNER.split('.')
# Allow for Python 2.5 relative paths # Allow for Python 2.5 relative paths

View File

@ -15,6 +15,7 @@ from django.core.cache import get_cache
from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning
from django.http import HttpResponse, HttpRequest from django.http import HttpResponse, HttpRequest
from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware from django.middleware.cache import FetchFromCacheMiddleware, UpdateCacheMiddleware
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import translation from django.utils import translation
from django.utils import unittest from django.utils import unittest
from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key from django.utils.cache import patch_vary_headers, get_cache_key, learn_cache_key
@ -379,21 +380,16 @@ class BaseCacheTests(object):
# manager to test this warning nicely. Since we can't do that # manager to test this warning nicely. Since we can't do that
# yet, the cleanest option is to temporarily ask for # yet, the cleanest option is to temporarily ask for
# CacheKeyWarning to be raised as an exception. # CacheKeyWarning to be raised as an exception.
_warnings_state = get_warnings_state()
warnings.simplefilter("error", CacheKeyWarning) warnings.simplefilter("error", CacheKeyWarning)
try:
# memcached does not allow whitespace or control characters in keys # memcached does not allow whitespace or control characters in keys
self.assertRaises(CacheKeyWarning, self.cache.set, 'key with spaces', 'value') self.assertRaises(CacheKeyWarning, self.cache.set, 'key with spaces', 'value')
# memcached limits key length to 250 # memcached limits key length to 250
self.assertRaises(CacheKeyWarning, self.cache.set, 'a' * 251, 'value') self.assertRaises(CacheKeyWarning, self.cache.set, 'a' * 251, 'value')
finally:
# The warnings module has no public API for getting the restore_warnings_state(_warnings_state)
# current list of warning filters, so we can't save that off
# and reset to the previous value, we have to globally reset
# it. The effect will be the same, as long as the Django test
# runner doesn't add any global warning filters (it currently
# does not).
warnings.resetwarnings()
warnings.simplefilter("ignore", PendingDeprecationWarning)
class DBCacheTests(unittest.TestCase, BaseCacheTests): class DBCacheTests(unittest.TestCase, BaseCacheTests):
def setUp(self): def setUp(self):

View File

@ -48,14 +48,14 @@ class AuthContextProcessorTests(TestCase):
fixtures = ['context-processors-users.xml'] fixtures = ['context-processors-users.xml']
def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.auth.models') module='django.contrib.auth.models')
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.core.context_processors') module='django.core.context_processors')
def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)
def test_session_not_accessed(self): def test_session_not_accessed(self):
""" """

View File

@ -71,12 +71,12 @@ class CsrfMiddlewareTest(TestCase):
_secret_key_for_session_test= "test" _secret_key_for_session_test= "test"
def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.middleware.csrf') module='django.middleware.csrf')
def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)
def _get_GET_no_csrf_cookie_request(self): def _get_GET_no_csrf_cookie_request(self):
return TestingHttpRequest() return TestingHttpRequest()

View File

@ -315,14 +315,14 @@ class DeprecatedSyndicationFeedTest(FeedTestCase):
Tests for the deprecated API (feed() view and the feed_dict etc). Tests for the deprecated API (feed() view and the feed_dict etc).
""" """
def setUp(self): def setUp(self):
self.save_warnings_state()
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.syndication.feeds') module='django.contrib.syndication.feeds')
warnings.filterwarnings('ignore', category=DeprecationWarning, warnings.filterwarnings('ignore', category=DeprecationWarning,
module='django.contrib.syndication.views') module='django.contrib.syndication.views')
def tearDown(self): def tearDown(self):
warnings.resetwarnings() self.restore_warnings_state()
warnings.simplefilter('ignore', PendingDeprecationWarning)
def test_empty_feed_dict(self): def test_empty_feed_dict(self):
""" """

View File

@ -20,6 +20,7 @@ from django.template import TemplateDoesNotExist, Context
from django.template.loaders.eggs import load_template_source as lts_egg from django.template.loaders.eggs import load_template_source as lts_egg
from django.template.loaders.eggs import Loader as EggLoader from django.template.loaders.eggs import Loader as EggLoader
from django.template import loader from django.template import loader
from django.test.utils import get_warnings_state, restore_warnings_state
from django.utils import unittest from django.utils import unittest
@ -68,13 +69,13 @@ class DeprecatedEggLoaderTest(unittest.TestCase):
}) })
self._old_installed_apps = settings.INSTALLED_APPS self._old_installed_apps = settings.INSTALLED_APPS
settings.INSTALLED_APPS = [] settings.INSTALLED_APPS = []
self._warnings_state = get_warnings_state()
warnings.filterwarnings("ignore", category=DeprecationWarning, warnings.filterwarnings("ignore", category=DeprecationWarning,
module='django.template.loaders.eggs') module='django.template.loaders.eggs')
def tearDown(self): def tearDown(self):
settings.INSTALLED_APPS = self._old_installed_apps settings.INSTALLED_APPS = self._old_installed_apps
warnings.resetwarnings() restore_warnings_state(self._warnings_state)
warnings.simplefilter("ignore", PendingDeprecationWarning)
def test_existing(self): def test_existing(self):
"A template can be loaded from an egg" "A template can be loaded from an egg"

View File

@ -26,6 +26,35 @@ class SkippingTestCase(TestCase):
self.assertRaises(ValueError, test_func) self.assertRaises(ValueError, test_func)
class SaveRestoreWarningState(TestCase):
def test_save_restore_warnings_state(self):
"""
Ensure save_warnings_state/restore_warnings_state work correctly.
"""
# In reality this test could be satisfied by many broken implementations
# of save_warnings_state/restore_warnings_state (e.g. just
# warnings.resetwarnings()) , but it is difficult to test more.
import warnings
self.save_warnings_state()
class MyWarning(Warning):
pass
# Add a filter that causes an exception to be thrown, so we can catch it
warnings.simplefilter("error", MyWarning)
self.assertRaises(Warning, lambda: warnings.warn("warn", MyWarning))
# Now restore.
self.restore_warnings_state()
# After restoring, we shouldn't get an exception. But we don't want a
# warning printed either, so we have to silence the warning.
warnings.simplefilter("ignore", MyWarning)
warnings.warn("warn", MyWarning)
# Remove the filter we just added.
self.restore_warnings_state()
__test__ = {"API_TEST": r""" __test__ = {"API_TEST": r"""
# Some checks of the doctest output normalizer. # Some checks of the doctest output normalizer.
# Standard doctests do fairly # Standard doctests do fairly