InsideDarkWeb.com

Pytest environment fixtures not seen by imported class

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?

Stack Overflow Asked by pmdaly on November 18, 2021

1 Answers

One Answer

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

Add your own answers!

Related Questions

Pass the dynamic variable when button is pressed

1  Asked on September 19, 2020 by francy

 

detect a table part from entire image in python

5  Asked on September 19, 2020 by suji

   

C# Change number of decimals show, but it always skips a number

0  Asked on September 18, 2020 by theoverly

   

Custom font bold weight not working in Dompdf

1  Asked on September 17, 2020 by user13286

   

How to use has one through in laravel?

0  Asked on September 17, 2020 by ahz

       

TemplateRef type checking/declaring type

1  Asked on September 17, 2020 by petr-averyanov

   

What is the UIButton Navigation push equivalent in SwiftUI

1  Asked on September 17, 2020 by realtechygod

 

maven enforcer does not honor rules

2  Asked on September 14, 2020 by mr

     

Ask a Question

Get help from others!

© 2021 InsideDarkWeb.com. All rights reserved.