Stack Overflow Asked by pmdaly on November 18, 2021
I’m trying to set up pytest so that whenever I run my tests (locally or in github actions), the environment variables all point to files and locations in my test directory instead of wherever they’re set to based on the user.
The problem is, the fixture changes are visible if I add an ipdb
trace in the test_database
function and print os.getenv('DB_URL')
but the assert will always fail because the DataBase
object always has the original non-mocked url (set in .bash_profile
).
database.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'
How do I globally set environment variables so all objects see the same envs?
As others have mentioned in your comment that class variables to be avoided for this assignment because it's a constant which gets assigned the moment the import statement is scanned.
To better understand this situation, try placing the from repo import DataBase
inside your method
def test_database():
Like this:
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!
Now, when you place the from repo import Database
at the start of the file, pytest would scan and start reading all the imports and starts initialising the blueprints and sets the value of router the moment its imported.
Read: When is the class variable initialised in Python?
So the ideal way would be to avoid maybe such important initialisation and assing the same in the constructor of the Database
class. Thus ensuring it does calculate when needed.
I feel, I for one like to think of it like Explicit is better than implicit.
from the Zen Of Python and do it like:
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
Answered by Nagaraj Tantri on November 18, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP