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

时间:2015-07-02 21:46:05

标签: python django environment-variables foreman

我希望能够在我的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中,它没有办法(我知道)来设置它。

我怎样才能解决这个问题?

9 个答案:

答案 0 :(得分:28)

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

您应该在python的标准库unittest.mock中使用patch.dict()。它可以用作上下文管理器,装饰器或类装饰器。请参阅以下从官方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

答案 1 :(得分:14)

正如@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语句的持续时间内正确设置环境变量。

答案 2 :(得分:4)

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

Python3.6 environment on gitlab ci

更好的解决方案是erewok建议的,需要在python3中使用unittest.mock

假设使用unittest

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

```

答案 3 :(得分:3)

如果要在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):

答案 4 :(得分:1)

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

请参阅此处的文档:

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

我建议将py.test作为测试运行器,因为它支持不同类型的测试类甚至简单的函数,并且设置在测试之前和之后运行的灯具或其他代码非常容易。

答案 5 :(得分:1)

本文说明了所有内容,以下代码段对我有用 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")

答案 6 :(得分:0)

旧问题,但它出现在谷歌搜索中,现有的答案都不合适。如果你正在使用pytest,可以使用pytest's monkeypatching functionality设置/恢复env变种。

答案 7 :(得分:0)

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

我可以使用以下内容更改env变量:

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

现在我的env变量PARTNER_CODEsos

答案 8 :(得分:0)

全程说明Mock Environment Variables in Python’s unittest https://adamj.eu/tech/2020/10/13/how-to-mock-environment-variables-with-pythons-unittest/