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 :)
Using pytest-env pluginWe can use this plugin to set environment variables that don't really matter to the function implementations.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With