Pytest is Python’s de-facto testing framework, built around plain assert statements, fixtures for setup/teardown, and a plugin ecosystem (coverage, freezing time, mocking).
Monkeypatching a Method
The monkeypatch fixture replaces an attribute for the duration of a test and restores it automatically afterward. Wrapping it in an autouse=True fixture applies the patch to every test in the module without an explicit request.
import pytest
from your_module import Component
@pytest.fixture(autouse=True)
def patch_set_name(monkeypatch):
def mock_set_name(self, name):
pass # customize per test
monkeypatch.setattr(Component, "set_name", mock_set_name)Adding Directories to $PYTHONPATH
Rather than mutating sys.path in test code, declare extra import paths in config so every test run picks them up consistently. In pytest.ini:
[pytest]
pythonpath = ADDITIONAL_DIRECTORY1 ADDITIONAL_DIRECTORY2Or in pyproject.toml:
[tool.pytest.ini_options]
pythonpath = ["ADDITIONAL_DIRECTORY1", "ADDITIONAL_DIRECTORY2"]Fixture Cleanup
A fixture that returns only sets up state. Swap return for yield and put teardown code after the yield — pytest runs everything past it once the test finishes, even if the test raises.
@pytest.fixture
def resource():
r = acquire()
yield r
r.release() # runs after the test, even on failureUsing a Fixture Inside pytest.mark.parametrize
parametrize values are resolved before fixtures run, so you can’t pass a fixture directly as a parameter. The workaround is the built-in request fixture, which exposes getfixturevalue(fixture_name: str) to resolve a fixture by name at test time.
@pytest.mark.parametrize("fixture_name", ["fixture_a", "fixture_b"])
def test_something(request, fixture_name):
value = request.getfixturevalue(fixture_name)Coverage
Install pytest-cov and run with --cov:
pytest --cov-report html --cov=.Exclude folders (e.g. the test suite itself) via .coveragerc:
[run]
omit = tests/*Cheatsheet
Monkeypatching
monkeypatch.setattr(Component, "set_name", mock_set_name)Config
# pytest.ini
[pytest]
pythonpath = ADDITIONAL_DIRECTORY1 ADDITIONAL_DIRECTORY2# pyproject.toml
[tool.pytest.ini_options]
pythonpath = ["ADDITIONAL_DIRECTORY1", "ADDITIONAL_DIRECTORY2"]Fixtures
yield r # instead of return, for teardown after
request.getfixturevalue(fixture_name) # resolve a fixture by nameCoverage
pytest --cov-report html --cov=. # requires pytest-cov# .coveragerc
[run]
omit = tests/*