如何在更改env变量后正确导入fixture中的对象

时间:2017-12-30 16:25:02

标签: python flask pytest monkeypatching

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

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

两个灯具都设置了env变量,然后在将配置对象传递给测试函数之前导入它。

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

似乎第二个灯具不会导入配置对象,而是重用cleanConfig灯具创建的灯具。如何强制夹具重新导入配置对象?

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,
    ...
}

1 个答案:

答案 0 :(得分:0)

我终于找到了解决问题的方法。通过使用reload()函数,您可以在更改内容(在这种情况下加载的env变量)后再次导入模块。为了能够使用它,我必须将导入更改为配置模块,而不是之前导入的配置字典,因为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