django 在单元测试中设置环境变量

django setting environment variables in unittest tests

我希望能够在我的 Django 应用程序中设置环境变量,以便能够进行测试 运行。例如,我的观点依赖于几个 API 键。

有一些方法可以 override settings during testing,但我不想在 settings.py 中定义它们,因为这是一个安全问题。

我已经尝试在我的设置函数中设置这些环境变量,但这并不能为 Django 应用程序提供值。

class MyTests(TestCase):
    def setUp(self):
        os.environ['TEST'] = '123'  # doesn't propogate to app

当我在本地测试时,我只有一个 .env 文件 运行 和

foreman start -e .env web

os.environ 提供值。但是在 Django 的 unittest.TestCase 中,它没有办法(据我所知)来设置它。

我该如何解决这个问题?

我使用 py.test 作为我的测试运行器,它允许您创建一个 pytest.ini 文件,您可以在其中指定要在 运行 测试时使用的特定设置文件。

在此处查看相关文档:

http://pytest-django.readthedocs.org/en/latest/configuring_django.html#pytest-ini-settings

我一般推荐 py.test 作为测试运行器,因为它支持不同类型的测试 类 甚至是简单的功能,并且设置 fixture 或其他运行之前的代码非常容易并经过测试。

正如@schillingt 在评论中指出的那样,EnvironmentVarGuard 是正确的方法。

from test.test_support import EnvironmentVarGuard # Python(2.7 < 3)
from test.support import EnvironmentVarGuard # Python >=3
from django.test import TestCase

class MyTestCase(TestCase):
    def setUp(self):
        self.env = EnvironmentVarGuard()
        self.env.set('VAR', 'value')

    def test_something(self):
        with self.env:
            # ... perform tests here ... #
            pass

这会在上下文对象 with 语句期间正确设置环境变量。

老问题,但它出现在 Google 搜索中,现有答案都不合适。如果您使用的是 pytest,环境变量可以是 set/restored 使用 pytest's monkeypatching functionality.

test.support.EnvironmentVarGuard 是一个内部的 API,可能会随着版本的改变而改变(向后不兼容)。 事实上,整个 test 包仅供内部使用。 在测试包文档页面上明确说明它用于核心库的内部测试,而不是 public API。 (见下面的链接)

您应该在 python 的标准库 unittest.mock 中使用 patch.dict()。它可以用作上下文管理器、装饰器或 class 装饰器。请参阅下面从官方 Python 文档复制的示例代码。

import os
from unittest.mock import patch
with patch.dict('os.environ', {'newkey': 'newvalue'}):
    print(os.environ['newkey'])  # should print out 'newvalue'
    assert 'newkey' in os.environ  # should be True
assert 'newkey' not in os.environ  # should be True

更新:对于那些没有仔细阅读文档并且可能错过了注意事项的人,请在

阅读更多 test 软件包说明

https://docs.python.org/2/library/test.html

https://docs.python.org/3/library/test.html

如果您像这样在 Django 的 settings.py 文件中加载环境变量:

import os
ENV_NAME = os.environ.get('ENV_NAME', 'default')

你可以使用这个:

from django.test import TestCase, override_settings

@override_settings(ENV_NAME="super_setting")
def test_...(self):

最初,我的环境变量 PARTNER_CODE 设置为 wow

我可以使用以下方法更改环境变量:

from test.support import EnvironmentVarGuard
with EnvironmentVarGuard() as env:
   env['PARTNER_CODE'] = 'sos'

现在我的环境变量 PARTNER_CODE 显示 sos

使用 EnvironmentVarGuard 不是一个好的解决方案,因为它在某些环境中失败而在其他环境中有效。请参阅下面的示例。

erewok 提出的更好的解决方案需要使用 python3 中的 unittest.mock

假设使用单元测试

from unittest.mock import patch
class TestCase(unittest.TestCase):

    def setUp(self):
        self.env = patch.dict('os.environ', {'hello':'world'})

    def test_scenario_1(self):
        with self.env:
            self.assertEqual(os.environ.get('hello'), 'world')

```

这篇文章解释了所有,下面的片段对我有用 How to Mock Environment Variables in Python’s unittest

      import os
    from unittest import TestCase, mock

class SettingsTests(TestCase):
    @classmethod
    def setUpClass(cls):
        cls.env_patcher = mock.patch.dict(os.environ, {"FROBNICATION_COLOUR": "ROUGE"})
        cls.env_patcher.start()

        super().setUpClass()

    @classmethod
    def tearDownClass(cls):
        super().tearDownClass()

        cls.env_patcher.stop()

    def setUp(self):
        super().setUp()
        self.assertEqual(os.environ["FROBNICATION_COLOUR"], "ROUGE")

    def test_frobnication_colour(self):
        self.assertEqual(os.environ["FROBNICATION_COLOUR"], "ROUGE")

一路指点Mock Environment Variables in Python’s unittesthttps://adamj.eu/tech/2020/10/13/how-to-mock-environment-variables-with-pythons-unittest/