Задать вопрос

Тел: +7 965 3737 888





TestSettingsManager: temporarily change settings for tests

<p>This TestSettingsManager class takes some of the pain out of making temporary changes to settings for the purposes of a unittest or doctest.  It will keep track of the original settings and let you easily revert them back when you're done.  </p>
<p>It also handles re-syncing the DB if you modify INSTALLED_APPS, which is especially handy if you have some test-only models in tests/models.py.  This makes it easy to dynamically get those models synced to the DB before running your tests.</p>
<p>Sample doctest usage, for testing an app called "app_under_test," that has a tests/ sub-module containing a urls.py for testing URLs, a models.py with some testing models, and a templates/ directory with test templates:</p>
&gt;&gt;&gt; from test_utils import TestManager; mgr = TestManager()
&gt;&gt;&gt; import os
&gt;&gt;&gt; mgr.set(INSTALLED_APPS=('django.contrib.contenttypes',
...                         'django.contrib.sessions',
...                         'django.contrib.auth',
...                         'app_under_test',
...                         'app_under_test.tests'),
...         ROOT_URLCONF='app_under_test.tests.urls',
...         TEMPLATE_DIRS=(os.path.join(os.path.dirname(__file__),
...                                     'templates'),))

<p>...do your doctests...</p>
&gt;&gt;&gt; mgr.revert()

Вопрос полезен? Да0/Нет0

Ответы (9):

Ответ полезен? Да0/Нет0

Nice, thanks.

A note about NO_SETTING: setting it to something unlikely and then using == for comparison is less than ideal, because the unlikely value ('!', None) could be used in some remote setting.

A better approach is to create a new object for it, for example NO_SETTING = object(), and then using ≪is≫ for comparison. This is cleaner and safer, because Python will make sure no other value will ever evaluate true for ≪x is NO_SETTING≫.

Ответ полезен? Да0/Нет0

Note that the syncdb portion of this will only work in Django 1.1+ if you subclass from TransactionTestCase, which will slow your tests significantly. I don't really recommend the use of this snippet anymore.

Ответ полезен? Да0/Нет0

Really nice, very useful snippet! Thanks!

Ответ полезен? Да0/Нет0

@carljim: I guess I was wrong, syncdb method was working just fine. But I had to subclass TransactionTestCase in order to get tables for new models created.

Ответ полезен? Да0/Нет0

@carljim: it complains that ImproperlyConfigured: App with label testapp could not be found when I modify INSTALLED_APPS (Django 1.1). syncdb below seems to work:

def syncdb(self):
    loading.cache.loaded = False
    loading.cache.app_store = SortedDict()
    loading.cache.app_models = SortedDict()
    loading.cache.app_errors = {}
    loading.cache.handled = {}
    loading.cache.postponed = []
    call_command('syncdb', verbosity=0)

Ответ полезен? Да0/Нет0

Hmm, that solution doesn't seem like it would cover my use cases. I often have particular apps that need particular test settings (or additional test models), and it doesn't make sense to include those in the test settings for every single app.

Ответ полезен? Да0/Нет0

reanes's suggestion is great. Just remember to use

from django.conf import settings

rather than 'import settings' in your code that reads the settings, otherwise it'll just read the normal settings.py anyway.

Ответ полезен? Да0/Нет0

What I do is define a new test_settings.py file that looks like:

from settings import *
# add any additional or overridden settings and here
# you could add your automated syncdb stuff in here as well...

Then copy your manage.py to manage_test.py and change the line: "import settings" to "import test_settings as settings"

run manage_test.py instead of manage.py whenever you want to use your test settings.

Ответ полезен? Да0/Нет0

I kept having the feeling as I was writing this code that there MUST be some already-existing way to do this that I'm just too blind to see. Is there a better pattern for this that I'm missing?