首页 > 解决方案 > 导入的类看不到 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

conftest.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')

test_database.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'

如何全局设置环境变量,以便所有对象看到相同的环境?

标签: pythonpytestfixtures

解决方案


正如其他人在您的评论中提到的那样,该分配要避免使用类变量,因为它是一个常量,在扫描导入语句时会被分配。

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!

现在,当您将 放在from repo import Database文件的开头时,pytest 将扫描并开始读取所有导入并开始初始化蓝图并在导入时设置路由器的值。

阅读:何时在 Python 中初始化类变量?

因此,理想的方法是避免可能如此重要的初始化并在Database类的构造函数中进行相同的初始化。从而确保它在需要时进行计算。

我觉得,我喜欢把它想象成Explicit is better than implicit.Python Zen of 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

推荐阅读