From 0dc6420b3ebddd7bc2a0059b225d54ac19d4d901 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Fri, 6 May 2011 13:29:24 +0000 Subject: [PATCH] Added TestCase.settings context manager to easily override settings in test methods. git-svn-id: http://code.djangoproject.com/svn/django/trunk@16165 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/test/testcases.py | 19 +++++++++++- docs/topics/testing.txt | 25 ++++++++++++++++ tests/regressiontests/settings_tests/tests.py | 30 +++++++++++++++++-- 3 files changed, 70 insertions(+), 4 deletions(-) diff --git a/django/test/testcases.py b/django/test/testcases.py index 8ce3a7af0f..d85bc27218 100644 --- a/django/test/testcases.py +++ b/django/test/testcases.py @@ -2,11 +2,12 @@ from __future__ import with_statement import re import sys +from contextlib import contextmanager from functools import wraps from urlparse import urlsplit, urlunsplit from xml.dom.minidom import parseString, Node -from django.conf import settings +from django.conf import settings, UserSettingsHolder from django.core import mail from django.core.management import call_command from django.core.signals import request_started @@ -341,6 +342,22 @@ class TransactionTestCase(ut2.TestCase): """ restore_warnings_state(self._warnings_state) + @contextmanager + def settings(self, **options): + """ + A context manager that temporarily sets a setting and reverts + back to the original value when exiting the context. + """ + old_wrapped = settings._wrapped + override = UserSettingsHolder(settings._wrapped) + try: + for key, new_value in options.items(): + setattr(override, key, new_value) + settings._wrapped = override + yield + finally: + settings._wrapped = old_wrapped + def assertRedirects(self, response, expected_url, status_code=302, target_status_code=200, host=None, msg_prefix=''): """Asserts that a response redirected to a specific URL, and that the diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt index fbc6a7afe8..91d37b1bf1 100644 --- a/docs/topics/testing.txt +++ b/docs/topics/testing.txt @@ -1351,6 +1351,31 @@ For example:: This test case will flush *all* the test databases before running ``testIndexPageView``. +Overriding settings +~~~~~~~~~~~~~~~~~~~ + +.. method:: TestCase.settings + +.. versionadded:: 1.4 + +For testing purposes it's often useful to change a setting temporarily +and revert to the original value after running the testing code. For +this use case Django provides a standard `Python context manager`_ +:meth:`~django.test.TestCase.settings`, which can be used like this:: + + from django.test import TestCase + + class LoginTestCase(TestCase): + def test_overriding_settings(self): + with self.settings(LOGIN_URL='/other/login/'): + response = self.client.get('/sekrit/') + self.assertRedirects(response, '/other/login/?next=/sekrit/') + +This example will override the :setting:`LOGIN_URL` setting for the code +in the ``with`` block and reset its value to the previous state afterwards. + +.. _`Python context manager`: http://www.python.org/dev/peps/pep-0343/ + Emptying the test outbox ~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/regressiontests/settings_tests/tests.py b/tests/regressiontests/settings_tests/tests.py index 12e1e2d9f6..175a17d2ff 100644 --- a/tests/regressiontests/settings_tests/tests.py +++ b/tests/regressiontests/settings_tests/tests.py @@ -1,8 +1,31 @@ from django.conf import settings -from django.utils import unittest +from django.test import TestCase +class SettingsTests(TestCase): -class SettingsTests(unittest.TestCase): + def test_override(self): + settings.TEST = 'test' + self.assertEqual('test', settings.TEST) + with self.settings(TEST='override'): + self.assertEqual('override', settings.TEST) + self.assertEqual('test', settings.TEST) + del settings.TEST + + def test_override_change(self): + settings.TEST = 'test' + self.assertEqual('test', settings.TEST) + with self.settings(TEST='override'): + self.assertEqual('override', settings.TEST) + settings.TEST = 'test2' + self.assertEqual('test', settings.TEST) + del settings.TEST + + def test_override_doesnt_leak(self): + self.assertRaises(AttributeError, getattr, settings, 'TEST') + with self.settings(TEST='override'): + self.assertEqual('override', settings.TEST) + settings.TEST = 'test' + self.assertRaises(AttributeError, getattr, settings, 'TEST') # # Regression tests for #10130: deleting settings. @@ -18,7 +41,8 @@ class SettingsTests(unittest.TestCase): self.assertRaises(TypeError, delattr, settings, '_wrapped') -class TrailingSlashURLTests(unittest.TestCase): + +class TrailingSlashURLTests(TestCase): settings_module = settings def setUp(self):