Ticket #15561: 15561.4.diff

File 15561.4.diff, 14.9 KB (added by Jannis Leidel, 13 years ago)

Extended docs.

  • django/test/testcases.py

    diff --git a/django/test/testcases.py b/django/test/testcases.py
    index d85bc27..bfa1aeb 100644
    a b from __future__ import with_statement  
    22
    33import re
    44import sys
    5 from contextlib import contextmanager
    65from functools import wraps
    76from urlparse import urlsplit, urlunsplit
    87from xml.dom.minidom import parseString, Node
    from django.db import (transaction, connection, connections, DEFAULT_DB_ALIAS,  
    1716from django.http import QueryDict
    1817from django.test import _doctest as doctest
    1918from django.test.client import Client
    20 from django.test.utils import get_warnings_state, restore_warnings_state
     19from django.test.utils import get_warnings_state, restore_warnings_state, override_settings
    2120from django.utils import simplejson, unittest as ut2
    2221from django.utils.encoding import smart_str
    2322
    class TransactionTestCase(ut2.TestCase):  
    342341        """
    343342        restore_warnings_state(self._warnings_state)
    344343
    345     @contextmanager
    346     def settings(self, **options):
     344    def settings(self, **kwargs):
    347345        """
    348346        A context manager that temporarily sets a setting and reverts
    349347        back to the original value when exiting the context.
    350348        """
    351         old_wrapped = settings._wrapped
    352         override = UserSettingsHolder(settings._wrapped)
    353         try:
    354             for key, new_value in options.items():
    355                 setattr(override, key, new_value)
    356             settings._wrapped = override
    357             yield
    358         finally:
    359             settings._wrapped = old_wrapped
     349        return override_settings(**kwargs)
    360350
    361351    def assertRedirects(self, response, expected_url, status_code=302,
    362352                        target_status_code=200, host=None, msg_prefix=''):
  • django/test/utils.py

    diff --git a/django/test/utils.py b/django/test/utils.py
    index bf1dc4f..1201dd4 100644
    a b import sys  
    22import time
    33import os
    44import warnings
    5 from django.conf import settings
     5from django.conf import settings, UserSettingsHolder
    66from django.core import mail
    77from django.core.mail.backends import locmem
    88from django.test import signals
    99from django.template import Template, loader, TemplateDoesNotExist
    1010from django.template.loaders import cached
    1111from django.utils.translation import deactivate
     12from django.utils.functional import wraps
    1213
    13 __all__ = ('Approximate', 'ContextList', 'setup_test_environment',
    14        'teardown_test_environment', 'get_runner')
     14
     15__all__ = (
     16    'Approximate', 'ContextList',  'get_runner', 'settings_override',
     17    'setup_test_environment', 'teardown_test_environment',
     18    'setup_test_template_loader', 'restore_template_loaders',
     19)
    1520
    1621RESTORE_LOADERS_ATTR = '_original_template_source_loaders'
    1722
    def restore_template_loaders():  
    160165    """
    161166    loader.template_source_loaders = getattr(loader, RESTORE_LOADERS_ATTR)
    162167    delattr(loader, RESTORE_LOADERS_ATTR)
     168
     169
     170class override_settings(object):
     171    """
     172    Acts as either a decorator, or a context manager.  If it's a decorator it
     173    takes a function and returns a wrapped function.  If it's a contextmanager
     174    it's used with the ``with`` statement.  In either event entering/exiting
     175    are called before and after, respectively, the function/block is executed.
     176    """
     177    def __init__(self, **kwargs):
     178        self.options = kwargs
     179        self.wrapped = settings._wrapped
     180
     181    def __enter__(self):
     182        self.enable()
     183
     184    def __exit__(self, exc_type, exc_value, traceback):
     185        self.disable()
     186
     187    def __call__(self, func):
     188        @wraps(func)
     189        def inner(*args, **kwargs):
     190            self.enable()
     191            result = func(*args, **kwargs)
     192            self.disable()
     193            return result
     194        return inner
     195
     196    def enable(self):
     197        override = UserSettingsHolder(settings._wrapped)
     198        for key, new_value in self.options.items():
     199            setattr(override, key, new_value)
     200        settings._wrapped = override
     201
     202    def disable(self):
     203        settings._wrapped = self.wrapped
  • docs/topics/testing.txt

    diff --git a/docs/topics/testing.txt b/docs/topics/testing.txt
    index 61e860c..f9739e5 100644
    a b this use case Django provides a standard `Python context manager`_  
    13761376    from django.test import TestCase
    13771377
    13781378    class LoginTestCase(TestCase):
    1379         def test_overriding_settings(self):
     1379
     1380        def test_login(self):
     1381
     1382            # First check for the default behavior
     1383            response = self.client.get('/sekrit/')
     1384            self.assertRedirects(response, '/accounts/login/?next=/sekrit/')
     1385
     1386            # Then override the LOGING_URL setting
    13801387            with self.settings(LOGIN_URL='/other/login/'):
    13811388                response = self.client.get('/sekrit/')
    13821389                self.assertRedirects(response, '/other/login/?next=/sekrit/')
    this use case Django provides a standard `Python context manager`_  
    13841391This example will override the :setting:`LOGIN_URL` setting for the code
    13851392in the ``with`` block and reset its value to the previous state afterwards.
    13861393
     1394.. function:: utils.override_settings
     1395
     1396In case you want to override a setting for just one test method or even the
     1397whole TestCase class, Django provides the
     1398:func:`django.test.utils.override_settings` decorator_. It's used like this::
     1399
     1400    from django.test import TestCase
     1401    from django.test.utils import override_settings
     1402
     1403    class LoginTestCase(TestCase):
     1404
     1405        @override_settings(LOGIN_URL='/other/login/')
     1406        def test_login(self):
     1407            response = self.client.get('/sekrit/')
     1408            self.assertRedirects(response, '/other/login/?next=/sekrit/')
     1409
     1410The decorator can also be applied to test case classes::
     1411
     1412    from django.test import TestCase
     1413    from django.test.utils import override_settings
     1414
     1415    class LoginTestCase(TestCase):
     1416
     1417        def test_login(self):
     1418            response = self.client.get('/sekrit/')
     1419            self.assertRedirects(response, '/other/login/?next=/sekrit/')
     1420
     1421    LoginTestCase = override_settings(LOGIN_URL='/other/login/')(LoginTestCase)
     1422
     1423On Python 2.6 and higher you can also use the well known decorator syntax to
     1424decorate the class::
     1425
     1426    from django.test import TestCase
     1427    from django.test.utils import override_settings
     1428
     1429    @override_settings(LOGIN_URL='/other/login/')
     1430    class LoginTestCase(TestCase):
     1431
     1432        def test_login(self):
     1433            response = self.client.get('/sekrit/')
     1434            self.assertRedirects(response, '/other/login/?next=/sekrit/')
     1435
    13871436.. _`Python context manager`: http://www.python.org/dev/peps/pep-0343/
     1437.. _`decorator`: http://www.python.org/dev/peps/pep-0318/
    13881438
    13891439Emptying the test outbox
    13901440~~~~~~~~~~~~~~~~~~~~~~~~
  • tests/regressiontests/mail/tests.py

    diff --git a/tests/regressiontests/mail/tests.py b/tests/regressiontests/mail/tests.py
    index 706b3af..5d5f52b 100644
    a b from StringIO import StringIO  
    99import tempfile
    1010import threading
    1111
    12 from django.conf import settings
    1312from django.core import mail
    1413from django.core.mail import (EmailMessage, mail_admins, mail_managers,
    1514        EmailMultiAlternatives, send_mail, send_mass_mail)
    1615from django.core.mail.backends import console, dummy, locmem, filebased, smtp
    1716from django.core.mail.message import BadHeaderError
    1817from django.test import TestCase
     18from django.test.utils import override_settings
    1919from django.utils.translation import ugettext_lazy
    20 from django.utils.functional import wraps
    21 
    22 
    23 def alter_django_settings(**kwargs):
    24     oldvalues = {}
    25     nonexistant = []
    26     for setting, newvalue in kwargs.iteritems():
    27         try:
    28             oldvalues[setting] = getattr(settings, setting)
    29         except AttributeError:
    30             nonexistant.append(setting)
    31         setattr(settings, setting, newvalue)
    32     return oldvalues, nonexistant
    33 
    34 
    35 def restore_django_settings(state):
    36     oldvalues, nonexistant = state
    37     for setting, oldvalue in oldvalues.iteritems():
    38         setattr(settings, setting, oldvalue)
    39     for setting in nonexistant:
    40         delattr(settings, setting)
    41 
    42 
    43 def with_django_settings(**kwargs):
    44     def decorator(test):
    45         @wraps(test)
    46         def decorated_test(self):
    47             state = alter_django_settings(**kwargs)
    48             try:
    49                 return test(self)
    50             finally:
    51                 restore_django_settings(state)
    52         return decorated_test
    53     return decorator
    5420
    5521
    5622class MailTests(TestCase):
    class MailTests(TestCase):  
    251217            shutil.rmtree(tmp_dir)
    252218        self.assertTrue(isinstance(mail.get_connection(), locmem.EmailBackend))
    253219
    254     @with_django_settings(
     220    @override_settings(
    255221        EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend',
    256222        ADMINS=[('nobody', 'nobody@example.com')],
    257223        MANAGERS=[('nobody', 'nobody@example.com')])
    class BaseEmailBackendTests(object):  
    323289    email_backend = None
    324290
    325291    def setUp(self):
    326         self.__settings_state = alter_django_settings(EMAIL_BACKEND=self.email_backend)
     292        self.settings_override = override_settings(EMAIL_BACKEND=self.email_backend)
     293        self.settings_override.enable()
    327294
    328295    def tearDown(self):
    329         restore_django_settings(self.__settings_state)
     296        self.settings_override.disable()
    330297
    331298    def assertStartsWith(self, first, second):
    332299        if not first.startswith(second):
    class BaseEmailBackendTests(object):  
    375342        self.assertEqual(message.get_payload(), "Content")
    376343        self.assertEqual(message["from"], "=?utf-8?q?Firstname_S=C3=BCrname?= <from@example.com>")
    377344
    378     @with_django_settings(MANAGERS=[('nobody', 'nobody@example.com')])
     345    @override_settings(MANAGERS=[('nobody', 'nobody@example.com')])
    379346    def test_html_mail_managers(self):
    380347        """Test html_message argument to mail_managers"""
    381348        mail_managers('Subject', 'Content', html_message='HTML Content')
    class BaseEmailBackendTests(object):  
    390357        self.assertEqual(message.get_payload(1).get_payload(), 'HTML Content')
    391358        self.assertEqual(message.get_payload(1).get_content_type(), 'text/html')
    392359
    393     @with_django_settings(ADMINS=[('nobody', 'nobody@example.com')])
     360    @override_settings(ADMINS=[('nobody', 'nobody@example.com')])
    394361    def test_html_mail_admins(self):
    395362        """Test html_message argument to mail_admins """
    396363        mail_admins('Subject', 'Content', html_message='HTML Content')
    class BaseEmailBackendTests(object):  
    405372        self.assertEqual(message.get_payload(1).get_payload(), 'HTML Content')
    406373        self.assertEqual(message.get_payload(1).get_content_type(), 'text/html')
    407374
    408     @with_django_settings(ADMINS=[('nobody', 'nobody+admin@example.com')],
    409                          MANAGERS=[('nobody', 'nobody+manager@example.com')])
     375    @override_settings(
     376        ADMINS=[('nobody', 'nobody+admin@example.com')],
     377        MANAGERS=[('nobody', 'nobody+manager@example.com')])
    410378    def test_manager_and_admin_mail_prefix(self):
    411379        """
    412380        String prefix + lazy translated subject = bad output
    class BaseEmailBackendTests(object):  
    421389        message = self.get_the_message()
    422390        self.assertEqual(message.get('subject'), '[Django] Subject')
    423391
    424     @with_django_settings(ADMINS=(), MANAGERS=())
     392    @override_settings(ADMINS=(), MANAGERS=())
    425393    def test_empty_admins(self):
    426394        """
    427395        Test that mail_admins/mail_managers doesn't connect to the mail server
    class FileBackendTests(BaseEmailBackendTests, TestCase):  
    501469    email_backend = 'django.core.mail.backends.filebased.EmailBackend'
    502470
    503471    def setUp(self):
    504         super(FileBackendTests, self).setUp()
    505472        self.tmp_dir = tempfile.mkdtemp()
    506         self.__settings_state = alter_django_settings(EMAIL_FILE_PATH=self.tmp_dir)
     473        self.addCleanup(shutil.rmtree, self.tmp_dir)
     474        self.settings_override = override_settings(EMAIL_FILE_PATH=self.tmp_dir)
     475        self.settings_override.enable()
     476        super(FileBackendTests, self).setUp()
    507477
    508478    def tearDown(self):
    509         restore_django_settings(self.__settings_state)
    510         shutil.rmtree(self.tmp_dir)
     479        self.settings_override.disable()
    511480        super(FileBackendTests, self).tearDown()
    512481
    513482    def flush_mailbox(self):
    class SMTPBackendTests(BaseEmailBackendTests, TestCase):  
    642611    @classmethod
    643612    def setUpClass(cls):
    644613        cls.server = FakeSMTPServer(('127.0.0.1', 0), None)
    645         cls.settings = alter_django_settings(
     614        cls.settings_override = override_settings(
    646615            EMAIL_HOST="127.0.0.1",
    647616            EMAIL_PORT=cls.server.socket.getsockname()[1])
     617        cls.settings_override.enable()
    648618        cls.server.start()
    649619
    650620    @classmethod
    651621    def tearDownClass(cls):
     622        cls.settings_override.disable()
    652623        cls.server.stop()
    653624
    654625    def setUp(self):
  • tests/regressiontests/settings_tests/tests.py

    diff --git a/tests/regressiontests/settings_tests/tests.py b/tests/regressiontests/settings_tests/tests.py
    index 750ccc6..d2f7f5c 100644
    a b  
    11from __future__ import with_statement
    2 import os
     2import os, sys
    33from django.conf import settings, global_settings
    44from django.test import TestCase
     5from django.test.utils import override_settings
     6from django.utils.unittest import skipIf
     7
     8
     9class SettingGetter(object):
     10    def __init__(self):
     11        self.test = getattr(settings, 'TEST', 'undefined')
     12
    513
    614class SettingsTests(TestCase):
    715
    class SettingsTests(TestCase):  
    2937            settings.TEST = 'test'
    3038        self.assertRaises(AttributeError, getattr, settings, 'TEST')
    3139
     40    @override_settings(TEST='override')
     41    def test_decorator(self):
     42        self.assertEqual('override', settings.TEST)
     43
     44    def test_context_manager(self):
     45        self.assertRaises(AttributeError, getattr, settings, 'TEST')
     46        override = override_settings(TEST='override')
     47        self.assertRaises(AttributeError, getattr, settings, 'TEST')
     48        override.enable()
     49        self.assertEqual('override', settings.TEST)
     50        override.disable()
     51        self.assertRaises(AttributeError, getattr, settings, 'TEST')
     52
     53    def test_class_decorator(self):
     54        self.assertEqual(SettingGetter().test, 'undefined')
     55        DecoratedSettingGetter = override_settings(TEST='override')(SettingGetter)
     56        self.assertEqual(DecoratedSettingGetter().test, 'override')
     57        self.assertRaises(AttributeError, getattr, settings, 'TEST')
     58
     59    @skipIf(sys.version_info[:2] < (2, 6), "Python version is lower than 2.6")
     60    def test_new_class_decorator(self):
     61        self.assertEqual(SettingGetter().test, 'undefined')
     62        @override_settings(TEST='override')
     63        class DecoratedSettingGetter(SettingGetter):
     64            pass
     65        self.assertEqual(DecoratedSettingGetter().test, 'override')
     66        self.assertRaises(AttributeError, getattr, settings, 'TEST')
     67
     68
    3269    #
    3370    # Regression tests for #10130: deleting settings.
    3471    #
Back to Top