diff --git a/AUTHORS b/AUTHORS index a5bb3403995..95f763a96b5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -86,6 +86,7 @@ Endre Galaczi Eric Hunsberger Eric Siegerman Erik M. Bray +Evan Kepner Fabien Zarifian Fabio Zadrozny Feng Ma diff --git a/changelog/5250.doc.rst b/changelog/5250.doc.rst new file mode 100644 index 00000000000..1b4c564a0a4 --- /dev/null +++ b/changelog/5250.doc.rst @@ -0,0 +1 @@ +Expand docs on use of ``setenv`` and ``delenv`` with ``monkeypatch``. diff --git a/doc/en/monkeypatch.rst b/doc/en/monkeypatch.rst index 1a69c3a429d..b45ad07c1a9 100644 --- a/doc/en/monkeypatch.rst +++ b/doc/en/monkeypatch.rst @@ -16,7 +16,7 @@ and a discussion of its motivation. Simple example: monkeypatching functions ---------------------------------------------------- +---------------------------------------- If you want to pretend that ``os.expanduser`` returns a certain directory, you can use the :py:meth:`monkeypatch.setattr` method to @@ -38,8 +38,8 @@ Here our test function monkeypatches ``os.path.expanduser`` and then calls into a function that calls it. After the test function finishes the ``os.path.expanduser`` modification will be undone. -example: preventing "requests" from remote operations ------------------------------------------------------- +Global patch example: preventing "requests" from remote operations +------------------------------------------------------------------ If you want to prevent the "requests" library from performing http requests in all your tests, you can do:: @@ -81,6 +81,80 @@ so that any attempts within tests to create http requests will fail. See issue `#3290 `_ for details. +Monkeypatching environment variables +------------------------------------ + +If you are working with environment variables you often need to safely change the values +or delete them from the system for testing purposes. ``Monkeypatch`` provides a mechanism +to do this using the ``setenv`` and ``delenv`` method. Our example code to test: + +.. code-block:: python + + # contents of our original code file e.g. code.py + import os + + + def get_os_user_lower(): + """Simple retrieval function. + Returns lowercase USER or raises EnvironmentError.""" + username = os.getenv("USER") + + if username is None: + raise EnvironmentError("USER environment is not set.") + + return username.lower() + +There are two potential paths. First, the ``USER`` environment variable is set to a +value. Second, the ``USER`` environment variable does not exist. Using ``monkeypatch`` +both paths can be safely tested without impacting the running environment: + +.. code-block:: python + + # contents of our test file e.g. test_code.py + import pytest + + + def test_upper_to_lower(monkeypatch): + """Set the USER env var to assert the behavior.""" + monkeypatch.setenv("USER", "TestingUser") + assert get_os_user_lower() == "testinguser" + + + def test_raise_exception(monkeypatch): + """Remove the USER env var and assert EnvironmentError is raised.""" + monkeypatch.delenv("USER", raising=False) + + with pytest.raises(EnvironmentError): + _ = get_os_user_lower() + +This behavior can be be moved into ``fixture`` structures and shared across tests: + +.. code-block:: python + + import pytest + + + @pytest.fixture + def mock_env_user(monkeypatch): + monkeypatch.setenv("USER", "TestingUser") + + + @pytest.fixture + def mock_env_missing(monkeypatch): + monkeypatch.delenv("USER", raising=False) + + + # Notice the tests reference the fixtures for mocks + def test_upper_to_lower(mock_env_user): + assert get_os_user_lower() == "testinguser" + + + def test_raise_exception(mock_env_missing): + with pytest.raises(EnvironmentError): + _ = get_os_user_lower() + + + .. currentmodule:: _pytest.monkeypatch API Reference