planetp
planetp

Reputation: 16065

Modifying Django settings in tests

From Django docs:

You shouldn’t alter settings in your applications at runtime. For example, don’t do this in a view:

from django.conf import settings

settings.DEBUG = True   # Don't do this!

The only place you should assign to settings is in a settings file.

I've noticed that Django testing code does alter settings. Why is it ok to do it there?

Upvotes: 7

Views: 7554

Answers (3)

Leopd
Leopd

Reputation: 42717

Changing the settings during tests is perfectly normal, expected, supported behavior. This is because you want to verify that your code works with lots of different settings. It's so normal in fact that the built-in method to do so has such a simple name it's a bit confusing to find in the docs:

e.g.

class QueueTests(TestCase):

    def test_both_modes(self):
        with self.settings(QUEUE_MODE='fast'):
             self.assertTrue(run_a_test())
             assert settings.QUEUE_MODE == 'fast'

        with self.settings(QUEUE_MODE='slow'):
             self.assertTrue(run_a_test())
             assert settings.QUEUE_MODE == 'slow'

Upvotes: 3

taras
taras

Reputation: 3695

Is it ok to change settings?

Short answer: No, unless you do it during the startup.

Long answer: Django docs are correct, you should not modify settings at runtime. This means, no settings modifications after the app has been started, like changing configuration in views.py, serializers.py, models.py or other modules you add during the development. But it is ok to modify settings if they depend on local variables if you do it at startup and you are fully aware of what happens.

Can you modify settings while testing?

Yes, if you think you need it. Feel free to rely on override_settings to change settings value for testing purposes in the unit tests, see example of usage here Also, everything that this decorator does - is overriding settings with provided values and restoring settings value after test has passed (decorated function executed).

Why Django does modify them while testing the code.

From what I see, they change settings only for testing purposes and the only thing they do - adding a local host to allowed host so they can test the code using a local domain. Examples like that seem pretty reasonable for me as change is done only once and during unit tests set up. Imagine having overrride_settings call every time, that would be monstrous.

General recommendation.

Try not to, there is no need to modify settings and if there is - think about it, maybe settings is not the right place for a mutable setting? If you want to modify settings at runtime - please be aware that settings might be cached somewhere, copied and accessed all over the place - this is a plenty of space for new bugs. There is nothing bad in it, except having an unexpected behavior of the system due to an old/new value of the modified setting.

Hope this makes sense.

Upvotes: 9

andyhasit
andyhasit

Reputation: 15289

The answer is in the wording:

You shouldn’t alter settings in your applications at runtime.

Unit test code is not part of your application, so that statement doesn't apply to unit tests.

Why is it ok to do it there?

As per above, it is perfectly OK to override settings during tests, provided you do it in a localised manner (because tests are sometimes run in a multi-threaded manner).

Here is how they recommend doing it:

from django.test import TestCase

class LoginTestCase(TestCase):

    def test_login(self):

         # First check for the default behavior
         response = self.client.get('/sekrit/')
         self.assertRedirects(response, '/accounts/login/?next=/sekrit/')

         # Then override the LOGIN_URL setting
         with self.settings(LOGIN_URL='/other/login/'):
             response = self.client.get('/sekrit/')
             self.assertRedirects(response, '/other/login/?next=/sekrit/')

See docs: https://docs.djangoproject.com/en/2.2/topics/testing/tools/#django.test.SimpleTestCase.settings

Upvotes: 4

Related Questions