When writing code it is always a good idea to write testable code or easy to test code. However, sometimes you need to test code, which is not as easy to test as wanted. A useful trick that can assist you while testing code is monkeypatching global variables.
Suppose you have the following script.py:
from pathlib import Path data_directory = Path(__file__).parent / "data" print(data_directory)
data_directory may be used for finding data resources or saving new files.
However, when testing this code, you do not want to modify the documents in the data directory.
Instead, a temporary directory should be used, where additional temporary files can be created.
To do so, the
data_directoryvariable needs to be overwritten in tests.
Fortunately, we can utilise pytest's monkeypatch fixture:
# test.py import script def test_overwrite_data_dir(tmp_path, monkeypatch) -> None: data_directory = tmp_path / "data" monkeypatch.setattr(script, "data_directory", data_directory) assert data_directory == script.data_directory
Pytest provides a context manager, which can be used to test that a certain piece of code raises an exception.
In order to test different input values and whether or not an exception is raised, pytest's parametrisation feature can be combined with
nullcontext from the contextlib module.
from contextlib import nullcontext as does_not_raise import pytest @pytest.mark.parametrize( "example_input,expectation", [ (3, does_not_raise()), (2, does_not_raise()), (1, does_not_raise()), (0, pytest.raises(ZeroDivisionError)), ], ) def test_division(example_input, expectation): """Test how much I know division.""" with expectation: assert (6 / example_input) is not None
Pytest provides you with the capability to create custom markers in order to select or deselect tests more gradually.
Suppose you want to mark all command-line interface-related tests with a custom
To do so, you need to register the marker first in your pytest.ini as follows:
[pytest] markers = cli: mark a test as cli-related.
Now, you can use the marker
cli to mark all command-line interface related tests with it as follows:
import pytest @pytest.mark.cli def test_some_cli_test(): pass
Selecting marked tests is as easy as running:
$ pytest -m cli
... or deselecting them by using pytest's "not"-keyword:
$ pytest -m "not cli"