199👍
EDIT: This answer applies if you want to change settings for a small number of specific tests.
Since Django 1.4, there are ways to override settings during tests:
https://docs.djangoproject.com/en/stable/topics/testing/tools/#overriding-settings
TestCase
will have a self.settings
context manager, and there will also be an @override_settings
decorator that can be applied to either a test method or a whole TestCase
subclass.
These features did not exist yet in Django 1.3.
If you want to change settings for all your tests, you’ll want to create a separate settings file for test, which can load and override settings from your main settings file. There are several good approaches to this in the other answers; I have seen successful variations on both hspander’s and dmitrii’s approaches.
53👍
You can do anything you like to the UnitTest
subclass, including setting and reading instance properties:
from django.conf import settings
class MyTest(unittest.TestCase):
def setUp(self):
self.old_setting = settings.NUM_LATEST
settings.NUM_LATEST = 5 # value tested against in the TestCase
def tearDown(self):
settings.NUM_LATEST = self.old_setting
Since the django test cases run single-threaded, however, I’m curious about what else may be modifying the NUM_LATEST value? If that “something else” is triggered by your test routine, then I’m not sure any amount of monkey patching will save the test without invalidating the veracity of the tests itself.
- [Django]-Constructing Django filter queries dynamically with args and kwargs
- [Django]-How to update an existing Conda environment with a .yml file
- [Django]-Login Page by using django forms
34👍
You can pass --settings
option when running tests
python manage.py test --settings=mysite.settings_local
- [Django]-Set up a scheduled job?
- [Django]-Django: guidelines for speeding up template rendering performance
- [Django]-Running a specific test case in Django when your app has a tests directory
26👍
Although overriding settings configuration on runtime might help, in my opinion you should create a separate file for testing. This saves lot of configuration for testing and this would ensure that you never end up doing something irreversible (like cleaning staging database).
Say your testing file exists in ‘my_project/test_settings.py’, add
settings = 'my_project.test_settings' if 'test' in sys.argv else 'my_project.settings'
in your manage.py. This will ensure that when you run python manage.py test
you use test_settings only. If you are using some other testing client like pytest, you could as easily add this to pytest.ini
- [Django]-Django apps aren't loaded yet when using asgi
- [Django]-How to use permission_required decorators on django class-based views
- [Django]-Best way to integrate SqlAlchemy into a Django project
20👍
Update: the solution below is only needed on Django 1.3.x and earlier. For >1.4 see slinkp’s answer.
If you change settings frequently in your tests and use Python ≥2.5, this is also handy:
from contextlib import contextmanager
class SettingDoesNotExist:
pass
@contextmanager
def patch_settings(**kwargs):
from django.conf import settings
old_settings = []
for key, new_value in kwargs.items():
old_value = getattr(settings, key, SettingDoesNotExist)
old_settings.append((key, old_value))
setattr(settings, key, new_value)
yield
for key, old_value in old_settings:
if old_value is SettingDoesNotExist:
delattr(settings, key)
else:
setattr(settings, key, old_value)
Then you can do:
with patch_settings(MY_SETTING='my value', OTHER_SETTING='other value'):
do_my_tests()
- [Django]-What is pip install -q -e . for in this Travis-CI build tutorial?
- [Django]-Backwards migration with Django South
- [Django]-Why am I getting this error in Django?
19👍
You can override setting even for a single test function.
from django.test import TestCase, override_settings
class SomeTestCase(TestCase):
@override_settings(SOME_SETTING="some_value")
def test_some_function():
or you can override setting for each function in class.
@override_settings(SOME_SETTING="some_value")
class SomeTestCase(TestCase):
def test_some_function():
- [Django]-Execute code when Django starts ONCE only?
- [Django]-Automatic creation date for Django model form objects
- [Django]-Good ways to sort a queryset? – Django
14👍
For pytest users.
The biggest issue is:
override_settings
doesn’t work with pytest.- Subclassing Django’s
TestCase
will make it work but then you can’t use pytest fixtures.
The solution is to use the settings
fixture documented here.
Example
def test_with_specific_settings(settings):
settings.DEBUG = False
settings.MIDDLEWARE = []
..
And in case you need to update multiple fields
def override_settings(settings, kwargs):
for k, v in kwargs.items():
setattr(settings, k, v)
new_settings = dict(
DEBUG=True,
INSTALLED_APPS=[],
)
def test_with_specific_settings(settings):
override_settings(settings, new_settings)
- [Django]-Checking for empty queryset in Django
- [Django]-Having Django serve downloadable files
- [Django]-Django error: got multiple values for keyword argument
13👍
@override_settings
is great if you don’t have many differences between your production and testing environment configurations.
In other case you’d better just have different settings files. In this case your project will look like this:
your_project
your_app
...
settings
__init__.py
base.py
dev.py
test.py
production.py
manage.py
So you need to have your most of your settings in base.py
and then in other files you need to import all everything from there, and override some options. Here’s what your test.py
file will look like:
from .base import *
DEBUG = False
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'app_db_test'
}
}
PASSWORD_HASHERS = (
'django.contrib.auth.hashers.MD5PasswordHasher',
)
LOGGING = {}
And then you either need to specify --settings
option as in @MicroPyramid answer, or specify DJANGO_SETTINGS_MODULE
environment variable and then you can run your tests:
export DJANGO_SETTINGS_MODULE=settings.test
python manage.py test
- [Django]-How to filter objects for count annotation in Django?
- [Django]-How do I use pagination with Django class based generic ListViews?
- [Django]-Django: accessing session variables from within a template?
7👍
I created a new settings_test.py file which would import everything from settings.py file and modify whatever is different for testing purpose.
In my case I wanted to use a different cloud storage bucket when testing.
settings_test.py:
from project1.settings import *
import os
CLOUD_STORAGE_BUCKET = 'bucket_name_for_testing'
manage.py:
def main():
# use seperate settings.py for tests
if 'test' in sys.argv:
print('using settings_test.py')
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project1.settings_test')
else:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'project1.settings')
try:
from django.core.management import execute_from_command_line
except ImportError as exc:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
) from exc
execute_from_command_line(sys.argv)
- [Django]-Django – How to use decorator in class-based view methods?
- [Django]-Embed YouTube video – Refused to display in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'
- [Django]-Django self-referential foreign key
3👍
Found this while trying to fix some doctests… For completeness I want to mention that if you’re going to modify the settings when using doctests, you should do it before importing anything else…
>>> from django.conf import settings
>>> settings.SOME_SETTING = 20
>>> # Your other imports
>>> from django.core.paginator import Paginator
>>> # etc
- [Django]-Django: Reverse for 'detail' with arguments '('',)' and keyword arguments '{}' not found
- [Django]-How to get the currently logged in user's id in Django?
- [Django]-Is it better to use path() or url() in urls.py for django 2.0?
2👍
I’m using pytest.
I managed to solve this the following way:
import django
import app.setting
import modules.that.use.setting
# do some stuff with default setting
setting.VALUE = "some value"
django.setup()
import importlib
importlib.reload(app.settings)
importlib.reload(modules.that.use.setting)
# do some stuff with settings new value
- [Django]-Set up a scheduled job?
- [Django]-Django FileField upload is not working for me
- [Django]-You are trying to add a non-nullable field 'new_field' to userprofile without a default
2👍
You can override settings in test in this way:
from django.test import TestCase, override_settings
test_settings = override_settings(
DEFAULT_FILE_STORAGE='django.core.files.storage.FileSystemStorage',
PASSWORD_HASHERS=(
'django.contrib.auth.hashers.UnsaltedMD5PasswordHasher',
)
)
@test_settings
class SomeTestCase(TestCase):
"""Your test cases in this class"""
And if you need these same settings in another file you can just directly import test_settings
.
- [Django]-Django Reverse with arguments '()' and keyword arguments '{}' not found
- [Django]-Django dump data for a single model?
- [Django]-ImproperlyConfigured: You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings
0👍
If you have multiple test files placed in a subdirectory (python package), you can override settings for all these files based on condition of presence of ‘test’ string in sys.argv
app
tests
__init__.py
test_forms.py
test_models.py
__init__.py:
import sys
from project import settings
if 'test' in sys.argv:
NEW_SETTINGS = {
'setting_name': value,
'another_setting_name': another_value
}
settings.__dict__.update(NEW_SETTINGS)
Not the best approach. Used it to change Celery broker from Redis to Memory.
- [Django]-ImproperlyConfiguredError about app_name when using namespace in include()
- [Django]-How to test auto_now_add in django
- [Django]-Django error – matching query does not exist
0👍
One setting for all tests in a testCase
class TestSomthing(TestCase):
def setUp(self, **kwargs):
with self.settings(SETTING_BAR={ALLOW_FOO=True})
yield
override one setting in the testCase
from django.test import override_settings
@override_settings(SETTING_BAR={ALLOW_FOO=False})
def i_need_other_setting(self):
...
Important
Even though you are overriding these settings this will not apply to settings that your server initialize stuff with because it is already initialized, to do that you will need to start django with another setting module.
- [Django]-Backwards migration with Django South
- [Django]-Name '_' is not defined
- [Django]-Django Server Error: port is already in use
0👍
I really like using a custom test runner (taken from @meshy’s answer over here), since:
- It doesn’t rely on command-line arguments (which could be forgotten).
- It doesn’t require modifying your actual test cases.
Put the following in myapp/test_runner.py
:
from django.conf import settings
from django.test.runner import DiscoverRunner
class MyTestRunner(DiscoverRunner):
def setup_test_environment(self):
super().setup_test_environment()
settings.NEWS_NUM_LATEST = 42
# ...any other settings you want to override...
and the following in project/settings.py
:
TEST_RUNNER = 'myapp.test_runner.MyTestRunner'
- [Django]-Sending an SMS to a Cellphone using Django
- [Django]-How to solve "Page not found (404)" error in Django?
- [Django]-Django auto_now and auto_now_add
0👍
If you don’t want to use the override_settings decorator you can use this syntax
with override_settings(CUSTOMER_ORDERS_ALLOWED=0):
# Test
- [Django]-How to reset Django admin password?
- [Django]-Unittest Django: Mock external API, what is proper way?
- [Django]-How to get the currently logged in user's id in Django?