Search code examples
pythonflaskpytestmonkeypatching

Pytest: monkeypatch not overruling environ variable


I'm trying to test my Flask APP, but constants which are set inside the Config class using environment variables (os.environ.get()), aren't overruled by monkeypatching.

My config.py:

from os import environ, path
from dotenv import load_dotenv

basedir = path.abspath(path.dirname(__file__))
load_dotenv(path.join(basedir, '.env'))

class Config:
    """
    Set Flask configuration from environment variables, if present.
    """

    # General Config
    MY_VARIABLE = environ.get("SOME_ENV_VARIABLE", "somedefault")

My __init__.py

from flask import Flask
from config import Config

def create_app():
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object(Config())

My tests/conftest.py

import pytest
from application import create_app

@pytest.fixture(autouse=True)
def env_setup(monkeypatch):
    monkeypatch.setenv("SOME_ENV_VARIABLE", "test")


@pytest.fixture()
def app():
    app = create_app()
    # other setup can go here
    yield app
    # clean up / reset resources here

My tests/test_config.py:

class TestConfig:
    def test_config_values(self, app):
        assert app.config.get("MY_VARIABLE") == "test"

I keep getting AssertionError: assert 'somedefault' == 'test'

If I add a method to the config class with a @property decorator, as described at https://flask.palletsprojects.com/en/2.2.x/config/#development-production, then everything seems to work ok, for that specific property. But for class constants, it doesn't. Any thoughts?


Solution

  • There are global variables which are instantiated from the environment at import time. The fixtures are applied after loading the test modules, so they kick in too late.

    In other words, this is executed before:

    MY_VARIABLE = environ.get("SOME_ENV_VARIABLE", "somedefault")
    

    This is executed after:

    monkeypatch.setenv("SOME_ENV_VARIABLE", "test")
    

    There are several way to go around that:

    1. don't execute environ.get at import time
    2. monkeypatch MY_VARIABLE instead of "SOME_ENV_VARIABLE"
    3. mock environment in pytest_sessionstart (but don't import the application from conftest.py, or it will still be too late)