'How to mock an environment variable that is referenced in an imported module?

I have created a file containing environment variables and I am writing a test for this file. The file ("my_variables.py") looks like:

import os

if os.getenv("VCAP_APPLICATION"):
    foo = os.getenv("foo")
else:
    foo = "bar"

In my test I am mocking the definition of the the "VCAP_APPLICATION" env var. I then assert if my_variables.foo is equal to "foo". This is not the case, as it is equal to "bar".

I think my mocked variable is not properly mocked when importing the module. This is why I tried to import the module after mocking my variables. My test looks like this:

import unittest
import os
from unittest.mock import patch

class MyTestCase(unittest.TestCase):

    @patch.dict(
        os.environ,
        { 
            "VCAP_APPLICATION": "True",
            "foo": "foo"
        }
    )
    def test_env_var(self):
        print(os.getenv("VCAP_APPLICATION")) # Returns True, so env var is mocked!
        import my_variables
        self.assertEqual(my_variables.foo, "foo") # Results in AssertionError

Asserting equality results in an AssertionError:

AssertionError: 'Bar' =! 'Foo'

I first had the import at the top of the file. I now placed it after mocking. How can I mock the env var so that my imported module uses that one?



Solution 1:[1]

since the os.getenv() runs at import time unittest cant mock the object. You're going to have to get hacky by setting the environment variables in the os module before importing my_variables:

import unittest
import os

class MyTestCase(unittest.TestCase):
    def test_env_var(self):
        os.environ["VCAP_APPLICATION"] = "True"
        os.environ["foo"] = "foo"
        import my_variables
        self.assertEqual(my_variables.foo, "foo")

Solution 2:[2]

I used something like this (still i haven't figured out how to solve the import statement inside test_env_var).

import os
import unittest
from unittest.mock import patch


class MyTestCase(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        """
        For future use
        """
        super().setUpClass()

        your_envs = {
            "VCAP_APPLICATION": "True",
            "foo": "foo"
        }

        cls.env = patch.dict(in_dict=os.environ, values=your_envs, clear=True)
        cls.env.start()

    @classmethod
    def tearDownClass(cls):
        """
        For future use
        """
        super().tearDownClass()
        cls.env.stop()

    def test_env_var(self):
        print(os.getenv("VCAP_APPLICATION"))  # Returns True, so env var is mocked!
        import my_variables
        self.assertEqual(my_variables.foo, "foo")  # Results in AssertionError


if __name__ == '__main__':
    unittest.main()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 testfile
Solution 2 Kots