更改环境变量后如何在夹具中正确导入对象
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
我正在为 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