简体   繁体   English

使用 pytest 测试常量声明

[英]Testing constants declarations using pytest

We have a Python 3.7 application that has a declared constants.py file that has this form:我们有一个 Python 3.7 应用程序,它有一个声明为以下形式的 constants.py 文件:

APP_CONSTANT_1 = os.environ.get('app-constant-1-value')

In a test.py we were hoping to test the setting of these constants using something like this (this is highly simplified but represents the core issue):在 test.py 中,我们希望使用类似这样的方法来测试这些常量的设置(这是高度简化的,但代表了核心问题):

class TestConfig:
    """General config tests"""

    @pytest.fixture
    def mock_os_environ(self, monkeypatch):
        """  """

        def mock_get(*args, **kwargs):
            return 'test_config_value'

        monkeypatch.setattr(os.environ, "get", mock_get)

    def test_mock_env_vars(self, mock_os_environ):
        import constants
        assert os.environ.get('app-constant-1-value') == 'test_config_value' #passes
        assert constants.APP_CONSTANT_1 == 'test_config_value' #fails

The second assertion fails as constants.constants.APP_CONSTANT_1 is None.第二个断言失败,因为 constants.constants.APP_CONSTANT_1 为 None。 Turns out that the constants.py seems to be loaded during pytest's 'collecting' phase and thus is already set by the time the test is run.事实证明,constants.py 似乎是在 pytest 的“收集”阶段加载的,因此在运行测试时已经设置好了。

What are we missing here?我们在这里缺少什么? I feel like there is a simple way to resolve this in pytest but haven't yet discovered the secret.我觉得在 pytest 中有一个简单的方法可以解决这个问题,但还没有发现这个秘密。 Is there some way to avoid loading the constants file prior to the tests being run?有什么方法可以避免在测试运行之前加载常量文件? Any ideas are appreciated.任何想法表示赞赏。

The problem is most likely that constants has been loaded before.问题很可能是之前已加载过constants To make sure it gets the patched value, you have to reload it:为确保它获得修补后的值,您必须重新加载它:

import os
from importlib import reload

import pytest
import constants

class TestConfig:
    """General config tests"""

    @pytest.fixture
    def mock_os_environ(self, monkeypatch):
        """  """
        monkeypatch.setenv('app-constant-1-value', 'test_config_value')
        reload(constants)

    def test_mock_env_vars(self, mock_os_environ):
        assert os.environ.get('app-constant-1-value') == 'test_config_value'
        assert app.APP_CONSTANT_1 == 'test_config_value'

Note that I used monkeypatch.setenv to specifically set the variable you need.请注意,我使用monkeypatch.setenv专门设置您需要的变量。 If you don't need to change all environment variables, this is easier to use.如果您不需要更改所有环境变量,这更容易使用。

Erm, I would avoid using constants.嗯,我会避免使用常量。 You can subclass os.environment for a start, and then use a mocked subclass for your unit tests, so you can have my_env.unique_env as a member variable.您可以先将 os.environment 子类化,然后使用模拟子类进行单元测试,因此您可以将 my_env.unique_env 作为成员变量。 You can then use eg.然后你可以使用例如。 import json to use a json configuration file without getting involved with hard coded python.导入 json 以使用 json 配置文件,而不涉及硬编码的 python。

The subclass can then hold the relevant variables (or methods if you prefer)然后子类可以保存相关变量(或方法,如果您愿意)

Being able to add a facade to os.environment provides you with the abstraction you are looking for, without any of the problems.能够为 os.environment 添加外观为您提供了您正在寻找的抽象,而没有任何问题。

Even is one is using a legacy/larger project, the advantage of using an adapter for access to the environment must be apparent.即使是使用遗留/更大的项目,使用适配器访问环境的优势也必须是显而易见的。

Since you are writing unit tests, there is an opportunity to use an adapter class in both the tests and the functions being tested.由于您正在编写单元测试,因此有机会在测试和正在测试的功能中使用适配器 class。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM