更改环境变量后如何在夹具中正确导入对象

How to correctly import object in fixture after changing env variables

我正在为 Flask 应用程序的配置文件编写测试。为了确保系统中设置的 env 变量不会影响测试结果,我使用 pytest 的 monkeypatch 来创建可预测的测试结果。

我在 'clean' 状态下测试配置文件一次,没有设置 env 变量的夹具,一次在 'fake' 配置中,用一个夹具让 monkeypatch 设置变量在 运行 测试之前。

两个装置都设置了 env 变量,然后导入配置对象,然后再将其传递给测试函数。

当配置对象加载到文档的头部而不是夹具内部时,两个夹具都使用基于实际系统环境变量的版本。

第二个 fixture 似乎没有导入配置对象,而是重用了 cleanConfig fixture 创建的那个。如何强制 fixture 重新导入配置对象?

test_config.py:

import pytest
from config import config

class TestConfigSettings(object):

@pytest.fixture(scope='function')
def cleanConfig(config_name, monkeypatch):
    def makeCleanConfig(config_name):

        monkeypatch.delenv('SECRET_KEY', raising=False)
        monkeypatch.delenv('DEV_DATABASE_URL', raising=False)

        from config import config
        configObject = config[config_name]

        return configObject
    return makeCleanConfig


@pytest.fixture(scope='function')
def fakeEnvConfig(config_name, monkeypatch):
    def makeFakeEnvConfig(config_name):

        monkeypatch.setenv('SECRET_KEY', 'fake difficult string')
        monkeypatch.setenv('DEV_DATABASE_URL', 'postgresql://fake:5432/fakeDevUrl')

        from config import config
        configObject = config[config_name]

        return configObject
    return makeFakeEnvConfig


def test_configObject_withDevelopmentConfig_containsCorrectSettings(self, cleanConfig):
    configObject = cleanConfig('development')

    assert configObject.SECRET_KEY == 'hard to guess string'
    assert configObject.DEBUG == True
    assert configObject.SQLALCHEMY_DATABASE_URI == None

def test_configObject_withDevelopmentConfigAndEnvSet_copiesEnvSettings(self, fakeEnvConfig):
    configObject = fakeEnvConfig('development')

    assert configObject.SECRET_KEY == 'fake difficult string'
    assert configObject.SQLALCHEMY_DATABASE_URI == 'postgresql://fake:5432/fakeDevUrl'

Config.py:

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'hard to guess string'

class DevelopmentConfig(Config):
    DEBUG = True
    SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URL')

config = {
    'default': DevelopmentConfig,
    'development': DevelopmentConfig,
    ...
}

我终于找到了解决问题的方法。通过使用 reload() 函数,您可以在更改内容(在本例中为加载的环境变量)后再次导入模块。为了能够使用它,我必须将导入更改为配置模块而不是我之前导入的配置字典,因为 reload() 对象仅适用于模块。 新代码:

import pytest
from importlib import reload
import config

class TestConfigSettings(object):

@pytest.fixture(scope='function')
def cleanConfig(config_name, monkeypatch):
    def makeCleanConfig(config_name):

        monkeypatch.delenv('SECRET_KEY', raising=False)
        monkeypatch.delenv('DEV_DATABASE_URL', raising=False)

        reload(config)
        configObject = config.config[config_name]

        return configObject
    return makeCleanConfig

@pytest.fixture(scope='function')
def fakeEnvConfig(config_name, monkeypatch):
    def makeFakeEnvConfig(config_name):

        monkeypatch.setenv('SECRET_KEY', 'fake difficult string')
        monkeypatch.setenv('DEV_DATABASE_URL', 'postgresql://fake:5432/fakeDevUrl')

        reload(config)
        configObject = config.config[config_name]

        return configObject
    return makeFakeEnvConfig