12

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.

Mihai
  • 2,835
  • 2
  • 28
  • 36

4 Answers4

7

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()
Alex Bliskovsky
  • 5,973
  • 7
  • 32
  • 41
  • You'd still have to restore the old `os.environ` if you're doing something else after the tests ran, but this is something that can be factored into a method, I guess. I'll accept this as an answer. – Mihai Jan 16 '15 at 15:54
5

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")
Tom Chapin
  • 3,276
  • 1
  • 29
  • 18
3

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

Zichen Wang
  • 1,294
  • 13
  • 22
1

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.

langlauf.io
  • 3,009
  • 2
  • 28
  • 45