模拟 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

django:使用 BInaryField 模拟标志字段

如何模拟 Django 模型对象(及其方法)?

Django:在 shell 中模拟 HTTP 请求

Django内置函数详解Httprequest详解(模拟搜索/模拟用户登陆/模拟上传文件功能)

在 Django 2 中模拟 RelatedManager