Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding Settings for unit tests in Django doesn't work properly

I tried to unit test my Django program and I would like to check several values for a few variables in my settings.py file.

In the documentation, the section "Overriding settings" is describing a way to do it. But, despite all my attempts, I miserably fail to make the changes available in the program while the test is running. Here is a summary of what I do on a minimal example:

First, create a new project:

$ pyvenv virtualenv
$ cd virtualenv/
$ . bin/activate
(virtualenv) $ pip install django
(virtualenv) $ django-admin startproject myapp
(virtualenv) $ cd myapp/

Then, add the following files.

File settings.py

...

TEST_VALUE = 'a'

File tests.py

from django.test import TestCase
from myapp.settings import TEST_VALUE

class CheckSettings(TestCase):

  def test_settings(self):
    self.assertEqual(TEST_VALUE, 'a')

  def test_modified_settings(self):
    with self.settings(TEST_VALUE='b'):
      self.assertEqual(TEST_VALUE, 'b')

When I run the tests, I get the following:

$ ./manage.py test
Creating test database for alias 'default'...
F.
======================================================================
FAIL: test_modified_settings (myapp.tests.CheckSettings)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/virtualenv/myapp/tests.py", line 12, in test_modified_settings
    self.assertEqual(TEST_VALUE, 'b')
AssertionError: 'a' != 'b'
----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
Destroying test database for alias 'default'...

As you may have noticed, the original value of TEST_VALUE is 'a', and I try to modify it through the self.settings(TEST_VALUE='b')... but, without success.

You may try it through an empty project (Django is 1.6.5).

So, what am I missing to get it work properly ?

like image 262
perror Avatar asked Mar 01 '15 22:03

perror


2 Answers

Just to sum up what I understood from the comment from Ismail Badawi, in fact, I was not calling properly the variable from the settings.py because I was using from myapp.settings import TEST_VALUE, where I should have call it using from django.conf import settings and then settings.TEST_VALUE.

So, here is a proper tests.py file:

from django.test import TestCase
from django.conf import settings

class CheckSettings(TestCase):

  def test_settings(self):
    self.assertEqual(settings.TEST_VALUE, 'a')

  def test_modified_settings(self):
    with self.settings(TEST_VALUE='b'):
      self.assertEqual(settings.TEST_VALUE, 'b')

And, here is the result of ./manage.py test:

$ ./manage.py test
Creating test database for alias 'default'...
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s

OK
Destroying test database for alias 'default'...

So, the lesson of this little story is to always get your settings values from django.conf and not from myapp.settings when you use it.

Note also that if you are using a cache, some values of your settings.py may be stored in it and could be masked by their cached value. For that, the documentation of Django on "Overriding settings" gives a hint to solve this kind of problem:

When overriding settings, make sure to handle the cases in which your app’s code uses a cache or similar feature that retains state even if the setting is changed. Django provides the django.test.signals.setting_changed signal that lets you register callbacks to clean up and otherwise reset state when settings are changed.

Thought, the way to implement it for real is not given. It could be a good question to ask next...

like image 110
perror Avatar answered Oct 07 '22 18:10

perror


You should use the @override_settings decorator. https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.utils.override_settings

like image 20
man2xxl Avatar answered Oct 07 '22 19:10

man2xxl