模拟 django 设置:AttributeError:“设置”对象没有属性“FOO”
Posted
技术标签:
【中文标题】模拟 django 设置:AttributeError:“设置”对象没有属性“FOO”【英文标题】:mocking django settings: AttributeError: 'Settings' object has no attribute 'FOO' 【发布时间】:2014-12-10 11:00:06 【问题描述】:settings
上的属性在使用后消失:
.... here settings.FOO does exist.
with mock.patch('django.conf.settings.FOO', 123, create=True):
...
... here settings.FOO is gone.
为什么会这样?
我发现了一个老 bug,但不敢相信它还活着,因为这个 bug 已经有四年了:
http://code.google.com/p/mock/issues/detail?id=59
我们使用 pypi 的 mock 1.0.1。
【问题讨论】:
你想在测试中这样做吗?也许你可以使用docs.djangoproject.com/en/1.6/topics/testing/tools/… 或@override_settings
为什么我在测试中使用mock? AFAIK mock 是为测试而制作的。我编写了一个库,该库可以通过多种方式进行配置。我经常使用mock,到目前为止效果很好。对我来说,使用 mock 比 override_settings 更容易,因为 mock 适用于所有 python 项目(不仅仅是 django 项目)。
我的问题是关于为什么你在这种情况下使用模拟,而不是项目:) 在这种特定情况下,你可以使用覆盖而不是模拟,因为你正在尝试模拟 django 设置。跨度>
@coldmind 模拟库是为模拟一切而设计的。模拟 django 设置有效,除非您使用 create=True。然后在模拟完成后删除该属性。这不应该发生。
在我对create=True
的回答中查看UPD
【参考方案1】:
考虑简单的函数:
testapp/views.py
:
from django.conf import settings
def return_settings_foo():
return settings.FOO
然后在shell中:
In [9]: from testapp import views
In [10]: print views.return_settings_foo()
test
In [11]:
接下来我们将模拟 settings.FOO:
In [11]: with mock.patch('testapp.views.settings.FOO', 'mocked'):
print views.return_settings_foo()
....:
mocked
因此,您必须在调用它的位置模拟设置模块(而不是它所在的位置),对于这种情况,它是 testapp/views
。
测试将是相同的:
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')
更新
还有一件事。当你在存在的属性上使用create=True
时,不管它是否存在,在__exit__
的上下文结束后都会被删除,你可以使用pdb
看到.所以你的 FOO attr 在上下文之后被删除了
> /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>
【讨论】:
我不明白这个:So, you must mock settings module where you are calling it, (NOT where it is located)
。我以这种方式多次使用了模拟库,它总是按照我想要的方式工作。
其实,你必须按照我描述的方式来模拟。您正在将设置导入特定模块,因此您需要模拟此模块中的设置路径,而不是 real 路径 django.conf.settings。这是正常的方式,在每个模拟教程中都有描述。以上是关于模拟 django 设置:AttributeError:“设置”对象没有属性“FOO”的主要内容,如果未能解决你的问题,请参考以下文章
Django 没有设置 MySQL ON DELETE = CASCADE