Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pytest modules using os.environ - How do I test it correctly?

currently I am writing some Webapp, but this time I want to learn how to write proper tests for it (using pytest) :)

A very common pattern I often see is to make the default configuration changeable using environment variables. Currently I am struggling how to test this properly.

I've prepared some demo:

./app
./app/conf.py
./conftest.py
./run.py
./tests
./tests/test_demo.py

My ./app/conf.py looks like this:

from os import environ

DEMO = environ.get('DEMO', 'demo')
TEST = environ.get('TEST', 'test')

Launching the ./run.py shows that the settings are indeed changeable:

from os import environ

environ['DEMO'] = 'not a demo'
environ['TEST'] = 'untested'

from app import conf

if __name__ == '__main__':

    print(conf.DEMO)
    print(conf.TEST)

It prints out not a demo and untested - as expected. Great. (Note that I set the environment variables before importing conf).

Now to the tests: The ./conftest.py is currently empty it just helps pytest to locate the modules inside the app folder.

The ./tests/test_demo.py contains the following:

def test_conf_defaults():
    from app import conf

    assert conf.DEMO == 'demo'
    assert conf.TEST == 'test'


def test_conf_changed(monkeypatch):
    monkeypatch.setenv('DEMO', 'tested demo')
    monkeypatch.setenv('TEST', 'demo test')

    from app import conf

    assert conf.DEMO == 'tested demo'
    assert conf.TEST == 'demo test'

    monkeypatch.undo()

If I run pytest now, test_conf_changed fails with 'demo' == 'tested demo' -> the monkeypatch function did not patch the environment.

If I swap both testing functions (so test_conf_changed runs first), the test_conf_defaults will fail with 'tested demo' == 'demo'.

How I interpret it, is - the first time conf gets imported it sticks there with it's initial settings..

How can I tell pytest to completely reimport conf each test function, after setting up the environment variables?

I am stuck there for two days now - and slowly I doubt if testing is worth the hassle - please prove me wrong :)

like image 218
spky Avatar asked Jun 18 '15 12:06

spky


People also ask

Does pytest set any environment variables?

Using pytest-env pluginWe can use this plugin to set environment variables that don't really matter to the function implementations.

How does pytest test discovery work?

Conventions for Python test discovery pytest implements the following standard test discovery: If no arguments are specified then collection starts from testpaths (if configured) or the current directory. Alternatively, command line arguments can be used in any combination of directories, file names or node ids.


1 Answers

Thanks for the hint, Evert (variables inside the conf module are set inside the global namespace, they stick around) - I think I got it now.

To test my code I have to explicitly reimport conf after setting the environment variables. Changing the code in ./tests/test_demo.py to this does the trick:

from importlib import reload

from app import conf


def test_conf_changed(monkeypatch):
    monkeypatch.setenv('DEMO', 'tested demo')
    monkeypatch.setenv('TEST', 'demo test')

    reload(conf)

    assert conf.DEMO == 'tested demo'
    assert conf.TEST == 'demo test'


def test_conf_defaults():

    reload(conf)

    assert conf.DEMO == 'demo'
    assert conf.TEST == 'test'

Thank you.

like image 93
spky Avatar answered Oct 07 '22 09:10

spky