After this lesson, you will be able to: Write tests with pytest: fixtures, parametrize, mocking, and coverage.
Tests are how you ship without fear. pytest is the standard.
Drop test_*.py files alongside your code.
# test_math.pyimport pytestfrom mymodule import add, dividedef test_add():assert add(2, 3) == 5def test_divide_by_zero():with pytest.raises(ZeroDivisionError):divide(10, 0)@pytest.mark.parametrize("a,b,expected", [(1, 1, 2),(0, 0, 0),(-1, 1, 0),])def test_add_cases(a, b, expected):assert add(a, b) == expected# Run: pytest# Run with coverage: pytest --cov=mymodule
Fixtures = setup helpers. Mocks = replace dependencies during tests.
import pytestfrom unittest.mock import patch, MagicMock@pytest.fixturedef sample_user():def test_uses_fixture(sample_user):assert sample_user["name"] == "Alex"# Mock external API@patch("mymodule.requests.get")def test_fetch(mock_get):mock_get.return_value = MagicMock(status_code=200,json=lambda: {"ok": True},)from mymodule import fetchassert fetch("http://x")["ok"] is Truemock_get.assert_called_once_with("http://x")
pip install pytest-cov. `pytest --cov=mypackage --cov-report=term-missing` shows uncovered lines. Aim for 60-80% on logic code (not getters/types). In CI: fail builds when coverage drops by more than X%. Use pytest + coverage.py + codecov.
Test files in src/ folder rather than tests/. Mixes prod + test code. Mocking everything until tests pass but real system is broken. Mock at the boundary only. Skipping pytest.raises. Catching with try/except in tests loses the pytest assertion. Hardcoded sleep() in tests. Use freezegun or pytest-asyncio properly.
Pick the canonical pytest pattern.
Sign in and purchase access to unlock this lesson.