pytest
02 / 02

Parametrize, Mocking & Coverage

Parametrize, Mocking & Coverage

Parametrize

import pytest

@pytest.mark.parametrize('a,b,expected', [
    (1, 2, 3),
    (4, 5, 9),
    (-1, 1, 0),
])
def test_add(a, b, expected):
    assert a + b == expected
    # Each tuple becomes a separate reported test case —
    # a failure points straight at the exact input that broke.

# Custom, readable test IDs instead of pytest's auto-generated ones
@pytest.mark.parametrize('email,valid', [
    ('a@b.com', True),
    ('not-an-email', False),
], ids=['valid-email', 'missing-at-sign'])
def test_email_validation(email, valid):
    assert is_valid_email(email) == valid

# Skip/xfail
@pytest.mark.skip(reason='not implemented yet')
def test_future_feature():
    ...

@pytest.mark.skipif(sys.platform == 'win32', reason='posix-only')
def test_symlinks():
    ...

@pytest.mark.xfail(reason='known bug, see #123', strict=True)
def test_known_bug():
    assert broken_function() == 42

Mocking & monkeypatch

# pytest-mock's `mocker` fixture — auto-unpatches after the test
def test_sends_email(mocker):
    mock_send = mocker.patch('myapp.email.send')
    register_user('alice@example.com')
    mock_send.assert_called_once_with('alice@example.com', subject='Welcome')

# Built-in monkeypatch fixture — scoped helpers, auto-restored
def test_reads_api_key(monkeypatch):
    monkeypatch.setenv('API_KEY', 'test-key-123')
    assert get_api_key() == 'test-key-123'

def test_missing_env_var(monkeypatch):
    monkeypatch.delenv('API_KEY', raising=False)
    with pytest.raises(RuntimeError):
        get_api_key()

# tmp_path — unique temp directory per test, cleaned up automatically
def test_writes_file(tmp_path):
    file = tmp_path / 'output.txt'
    write_report(file)
    assert file.read_text() == 'expected content'

# capsys — capture stdout/stderr; caplog — capture log records
def test_prints_summary(capsys):
    print_summary()
    captured = capsys.readouterr()
    assert 'Done' in captured.out

Coverage & CI

pip install pytest-cov pytest-xdist

# Coverage report
pytest --cov=myapp --cov-report=html --cov-report=term-missing
pytest --cov=myapp --cov-fail-under=80   # fail the build below 80%

# Parallel test run across CPUs — tests must be independent!
pytest -n auto

# doctest — run examples embedded in docstrings as real tests
pytest --doctest-modules myapp/

# Typical pyproject.toml config
# [tool.pytest.ini_options]
# testpaths = ["tests"]
# addopts = "-ra -q --strict-markers"
# markers = ["slow: marks slow tests"]

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free