0

Attributes on settings disapear after using this:

.... here settings.FOO does exist.

with mock.patch('django.conf.settings.FOO', 123, create=True):
    ...

... here settings.FOO is gone.

Why does this happen?

I found an old bug, but can't believe that it is still alive, since the bug is four years old:

http://code.google.com/p/mock/issues/detail?id=59

We use mock 1.0.1 from pypi.

5
  • You are trying to do this in test? Maybe you can use docs.djangoproject.com/en/1.6/topics/testing/tools/… or @override_settings Commented Oct 15, 2014 at 14:37
  • Why I use mock in tests? AFAIK mock was made for testing. I write a library and the library can be configured in many ways. I use mock very often and up to now it worked very well. For me it is easier to use mock than override_settings, since mock works in all python projects (not just django projects). Commented Oct 15, 2014 at 17:51
  • My question was about why you are using mock for this case, not for project :) And at this specific case you can use overriding instead of mock, because you are trying to mock django settings. Commented Oct 15, 2014 at 18:06
  • @coldmind the mock library is made for mocking everything. Mocking django settings works, except if you use create=True. Then the attribute gets removed after the mock has finished. This should not happen. Commented Oct 15, 2014 at 19:30
  • See UPD in my answer about create=True Commented Oct 15, 2014 at 19:50

1 Answer 1

2

Consider simple function:

testapp/views.py:

from django.conf import settings


def return_settings_foo():
    return settings.FOO

Then in shell:

In [9]: from testapp import views

In [10]: print views.return_settings_foo()
test

In [11]: 

Next we will mock settings.FOO:

In [11]: with mock.patch('testapp.views.settings.FOO', 'mocked'):
    print views.return_settings_foo()
   ....:     
mocked

So, you must mock settings module where you are calling it, (NOT where it is located) for this case it is testapp/views.

Test will be the same:

import mock

from django.test import TestCase

from testapp import views

class TestPrintFoo(TestCase):
    @mock.patch('testapp.views.settings.FOO', 'mocked')
    def test_print(self):
        result = views.return_settings_foo()
        self.assertEqual(result, 'mocked')

    def test_not_mocked_print(self):
        result = views.return_settings_foo()
        self.assertEqual(result, 'test')


UPD

One more thing. When you use create=True on attribute that exists, no matter, if it was existed or not, it will be deleted after context end in the __exit__, you can use pdb to see that. So your FOO attr deleted after context

> /usr/local/lib/python2.7/dist-packages/mock.py(1381)__exit__()
   1380         else:
-> 1381             delattr(self.target, self.attribute)
   1382             if not self.create and not hasattr(self.target, self.attribute):

ipdb> self.target, self.attribute
(<django.conf.LazySettings object at 0x7f48f067db10>, 'FOO')
ipdb> 
Sign up to request clarification or add additional context in comments.

2 Comments

I don't understand this: So, you must mock settings module where you are calling it, (NOT where it is located). I used the mock library several times this way and it always worked the way I want it to.
Actually, you have to mock in the way I described. You are importing settings to specific module, so you need to mock settings path in this module, not the real path django.conf.settings. It is the normal way, and it's described in every mock tutorial.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.