Search code examples
pythonpytestmonkeypatching

Testing constants declarations using pytest


We have a Python 3.7 application that has a declared constants.py file that has this form:

APP_CONSTANT_1 = os.environ.get('app-constant-1-value')

In a test.py we were hoping to test the setting of these constants using something like this (this is highly simplified but represents the core issue):

class TestConfig:
    """General config tests"""

    @pytest.fixture
    def mock_os_environ(self, monkeypatch):
        """  """

        def mock_get(*args, **kwargs):
            return 'test_config_value'

        monkeypatch.setattr(os.environ, "get", mock_get)

    def test_mock_env_vars(self, mock_os_environ):
        import constants
        assert os.environ.get('app-constant-1-value') == 'test_config_value' #passes
        assert constants.APP_CONSTANT_1 == 'test_config_value' #fails

The second assertion fails as constants.constants.APP_CONSTANT_1 is None. Turns out that the constants.py seems to be loaded during pytest's 'collecting' phase and thus is already set by the time the test is run.

What are we missing here? I feel like there is a simple way to resolve this in pytest but haven't yet discovered the secret. Is there some way to avoid loading the constants file prior to the tests being run? Any ideas are appreciated.


Solution

  • The problem is most likely that constants has been loaded before. To make sure it gets the patched value, you have to reload it:

    import os
    from importlib import reload
    
    import pytest
    import constants
    
    class TestConfig:
        """General config tests"""
    
        @pytest.fixture
        def mock_os_environ(self, monkeypatch):
            """  """
            monkeypatch.setenv('app-constant-1-value', 'test_config_value')
            reload(constants)
    
        def test_mock_env_vars(self, mock_os_environ):
            assert os.environ.get('app-constant-1-value') == 'test_config_value'
            assert app.APP_CONSTANT_1 == 'test_config_value'
    

    Note that I used monkeypatch.setenv to specifically set the variable you need. If you don't need to change all environment variables, this is easier to use.