Django 中单元测试的覆盖设置无法正常工作

Posted

技术标签:

【中文标题】Django 中单元测试的覆盖设置无法正常工作【英文标题】:Overriding Settings for unit tests in Django doesn't work properly 【发布时间】:2015-05-02 05:10:03 【问题描述】:

我尝试对我的 Django 程序进行单元测试,我想检查我的 settings.py 文件中几个变量的几个值。

在文档中,“Overriding settings”部分描述了一种方法。但是,尽管我进行了所有尝试,但在测试运行时,我仍然无法在程序中提供更改。以下是我在一个最小示例上所做的总结:

首先,新建一个项目:

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

然后,添加以下文件。

文件settings.py

...

TEST_VALUE = 'a'

文件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')

当我运行测试时,我得到以下信息:

$ ./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'...

您可能已经注意到,TEST_VALUE 的原始值为'a',我尝试通过self.settings(TEST_VALUE='b') 对其进行修改...但是没有成功。

你可以通过一个空项目(Django 是 1.6.5)来尝试。

那么,为了让它正常工作,我缺少什么?

【问题讨论】:

只是猜测,但也许您必须通过settings 访问设置——例如from testing_settings import settings,然后在你的断言中使用settings.TEST_VALUE。更改已导入的值似乎有点太神奇了。 实际上是from django.conf import settings @IsmailBadawi:该死,你是对的!!!总结一下,我是通过from myapp.settings import TEST_VALUEsettings.py 文件中获取变量,但实际上我应该像from django.conf import settings 然后settings.TEST_VALUE 那样做...谢谢你的提示!它帮助很大。 另外,请注意有一个 modify_settings() 装饰器。 docs.djangoproject.com/en/1.9/topics/testing/tools/… 【参考方案1】:

总结一下我从 Ismail Badawi 的评论中了解到的内容,事实上,我没有正确调用来自 settings.py 的变量,因为我使用的是 from myapp.settings import TEST_VALUE,我应该使用 from django.conf import settings 来调用它然后settings.TEST_VALUE

所以,这是一个正确的tests.py 文件:

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')

还有,这是./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'...

所以,这个小故事的教训是在使用时始终从django.conf 而不是myapp.settings 获取设置值。

另请注意,如果您使用缓存,您的 settings.py 的某些值可能会存储在其中,并且可能会被它们的缓存值屏蔽。为此,“Overriding settings”上的 Django 文档给出了解决此类问题的提示:

覆盖设置时,请确保处理应用代码使用缓存或类似功能的情况,即使设置更改也会保留状态。 Django 提供django.test.signals.setting_changed 信号,允许您注册回调以在设置更改时清理或重置状态。

想了一下,没有给出真正实现它的方法。下一个问题可能是个好问题......

【讨论】:

此外,如果您在模块级别使用其中一些设置(例如,将它们存储在一些全局变量中以便更快地查找/减少繁琐的访问),则必须根据 settings_changed 信号重新加载它们。在这里没有用,但认为值得添加它,因为它密切相关。 @spectras:是的,你说得对,我会记录下来。【参考方案2】:

您应该使用 @override_settings 装饰器。 https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.utils.override_settings

【讨论】:

以上是关于Django 中单元测试的覆盖设置无法正常工作的主要内容,如果未能解决你的问题,请参考以下文章

从 1.8 升级到 2.2.4 后,Django 无法创建用于单元测试的表

Django 单元测试 查看覆盖率

带有 Chai 错误的 Express 单元测试 = 发送后无法设置标头

DataJpaTest 无法在单元测试中更新

Gitlab - 由于 TLS10,我的单元测试无法正常工作

单元测试踩到的坑