How to Mock Environment Variables in Python

A context manager that injects and restores environment variables for isolated testing of config-dependent code.

Medium Python 3.9+ Aug 9, 2026 Auth & security at scale 14 views 0 copies

Python code

34 lines
Python 3.9+
import os

class EnvInjector:
    def __init__(self, mock_vars=None):
        self.mock_vars = mock_vars or {}
        self.original = {}

    def __enter__(self):
        for key, value in self.mock_vars.items():
            if key in os.environ:
                self.original[key] = os.environ[key]
            os.environ[key] = value
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        for key in self.mock_vars:
            if key in self.original:
                os.environ[key] = self.original.pop(key)
            else:
                os.environ.pop(key, None)


def get_config_from_env():
    return {
        "host": os.environ.get("APP_HOST", "localhost"),
        "port": int(os.environ.get("APP_PORT", "8080")),
        "debug": os.environ.get("APP_DEBUG", "false").lower() == "true",
    }


if __name__ == "__main__":
    with EnvInjector({"APP_HOST": "example.com", "APP_PORT": "3000", "APP_DEBUG": "true"}):
        print(get_config_from_env())
    print(get_config_from_env())

Output

stdout
{'host': 'example.com', 'port': 3000, 'debug': True}
{'host': 'localhost', 'port': 8080, 'debug': False}

How it works

The EnvInjector class implements the context manager protocol with __enter__ and __exit__. Inside __enter__, it saves any existing environment variable values to self.original before overriding them, and __exit__ restores or removes those variables when the with block exits. The get_config_from_env function reads config values with defaults, so it transparently picks up the mocked values inside the block and the real values outside. This pattern isolates environment-dependent code without leaking state, making tests deterministic and side-effect free.

Common mistakes

  • Forgetting to save original values, which breaks restoration after the block ends
  • Using `os.environ[key]` instead of `.get(key)` for variables that may not exist
  • Not handling multiple context managers nesting, which can corrupt saved state

Variations

  1. Use `unittest.mock.patch.dict(os.environ, {...})` for a one-liner alternative
  2. Apply `pytest`'s `monkeypatch.setenv` fixture for test-specific mocking

Real-world use cases

  • Unit-testing service config loading that reads secrets like API keys or database URLs from env vars.
  • Simulating different deployment environments (staging, production) in integration tests without changing the machine.
  • Validating fallback logic when required environment variables are missing or misconfigured in CI.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Auth & security at scale

Related tutorials and quizzes for this topic.