I have a test suite that gets executed as a part of a larger build framework, written in Python. Some of the tests require parameters, which I want to pass using environment variables.
Apparently the nosetests runner has an env
parameter, which does what I want, according to the documentation. It seems, however, that it does not work as thought it should?
Here's a minimal test script that exemplifies the problem:
#!/usr/bin/env python
# pip install nose
import os, nose, unittest
class Test(unittest.TestCase):
def test_env(self):
self.assertEquals(os.environ.get('HELLO'), 'WORLD')
if __name__ == '__main__':
nose.run(env={'HELLO': 'WORLD'})
The assertion fails, because the env
parameter does not get passed to the test. Does anyone know why?
NB: I worked around the problem by launching the console nosetests
tool:
#!/usr/bin/env python
import sys, os, nose, unittest, subprocess
class Test(unittest.TestCase):
def test_env(self):
self.assertEquals(os.environ.get('HELLO'), 'WORLD')
if __name__ == '__main__':
subprocess.Popen(['nosetests', sys.argv[0]],
env={'HELLO': 'WORLD'}).wait()
However, this feels like a kludge, and I'd still be interested in learning to use nose.run()
properly.
The way I solved this problem was by using the python-dotenv pip module. I found this to be cleaner and easier to manage than having to manually set and then unset each variable inside of the test launcher shell script.
First, run:
pip install python-dotenv
Now, create a file called .env.test
in your project root, and list environment variables in it (one on each line). For example:
FOO=bar
BAZ=qux
In a file called tests/configuration.py
, place these contents:
from dotenv import load_dotenv, find_dotenv
def setup_testing_environment():
load_dotenv(find_dotenv(".env.test", raise_error_if_not_found=True))
Now, whenever you have a test file, all you have to do is call the configuration.setup_testing_environment()
method at the very top to load in your test environment variables!
Here's a working example - create an example test file called ./tests/test_env_vars.py
, with these contents:
import os
import unittest
from tests.configuration import setup_testing_environment
setup_testing_environment()
class TestEnvironmentVars(unittest.TestCase):
def test_foo_env_var_exists(self):
self.assertEquals(os.getenv("FOO"), "bar")
def test_baz_env_var_exists(self):
self.assertEquals(os.getenv("BAZ"), "qux")
I came across the same type of situation where an environmental variable is required during testing.
I worked around using a bash script to set the environmental variable first, run the test, and then unset
the environmental variable.
In run_tests.sh
:
#!/bin/bash
export HELLO='WORLD'
nosetests -v
unset HELLO
Then in the tests/test_env.py
:
#!/usr/bin/env python
import os, unittest
class Test(unittest.TestCase):
def test_env(self):
self.assertEquals(os.environ.get('HELLO'), 'WORLD')
To run the test, do
$ bash run_tests.sh
I couldn't get env
to behave itself either, but I have come up with a solution that I consider slighly less kludgy than opening a subprocess. You can modify the os.environ
variable before you call nose.run()
, and as long as the tests are running in the same process, the tests will all see the modified os.environ
:
#!/usr/bin/env python
import os, nose, unittest
class Test(unittest.TestCase):
def test_env(self):
self.assertEquals(os.environ.get('HELLO'), 'WORLD')
if __name__ == '__main__':
os.environ["HELLO"] = "WORLD"
nose.run()
I looked at the nose sources (core.py and config.py) and traced the handling of the env argument. I think the env argument is not meant as you thought. It is not for setting or adding to the testee's environment. It is only for nose-specific configuration options. Yet, it would be nice to have the feature you (and me too) were looking for.
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