pmd*_*aly 4 python fixtures pytest
我正在尝试设置 pytest,以便每当我运行测试(本地或在 github 操作中)时,环境变量都指向我的测试目录中的文件和位置,而不是根据用户设置的位置。
问题是,如果我ipdb在test_database函数中添加跟踪并打印,夹具更改是可见的os.getenv('DB_URL'),但断言将始终失败,因为DataBase对象始终具有原始的非模拟 url(在 中设置.bash_profile)。
数据库.py
import h5py
import os
class DataBase:
route = os.environ.get('DB_URL')
def __init__(self):
self.connected = False
def connect(self):
if not connected:
self.db = h5py.File(self.route, 'r')
self.connected = True
Run Code Online (Sandbox Code Playgroud)
测试.py
import os
import pytest
@pytest.fixture(autouse=True)
def mock_test_env(monkeypatch):
cwd = os.getcwd()
monkeypatch.setenv('DB_URL', cwd + '/sample_db.hdf5')
Run Code Online (Sandbox Code Playgroud)
测试数据库.py
import pytest
from repo import DataBase
def test_database():
db = DataBase()
import ipdb; ipdb.set_trace()
'''
os.getenv('DB_URL') returns cwd + '/sample_db.hdf5'
db.route returns original database, not the sample one above
'''
assert db.connected = False, 'DataBase must be instantiated to connected == False'
Run Code Online (Sandbox Code Playgroud)
如何全局设置环境变量以使所有对象看到相同的环境?
正如其他人在评论中提到的那样,要避免进行此分配的类变量,因为它是在扫描 import 语句时被分配的常量。
为了更好地了解这种情况,请尝试将from repo import DataBase您的方法中
def test_database():
像这样:
import os
import pytest
@pytest.fixture(autouse=True)
def mock_test_env(monkeypatch):
cwd = os.getcwd()
monkeypatch.setenv('DB_URL', cwd + '/sample_db.hdf5')
def test_database(mock_test_env):
from repo import DataBase # <<< This here works
db = DataBase()
assert db.route == (os.getcwd() + '/sample_db.hdf5') # Works!
Run Code Online (Sandbox Code Playgroud)
现在,当您将 放在from repo import Database文件开头时,pytest 将扫描并开始读取所有导入,并开始初始化蓝图并在导入时设置 router 的值。
因此,理想的方法是避免如此重要的初始化并在构造函数中进行相同的赋值Database。从而确保它在需要时进行计算。
我觉得,我喜欢Explicit is better than implicit.从Python 之禅的角度来思考它,并这样做:
import h5py
import os
class DataBase:
def __init__(self):
self.route = os.environ.get('DB_URL')
self.connected = False
def connect(self):
if not connected:
self.db = h5py.File(self.route, 'r')
self.connected = True
Run Code Online (Sandbox Code Playgroud)