Установка и структура
pip install pytest
Тесты кладут в отдельную папку рядом с кодом:
myproject/
app/
utils.py
tests/
test_utils.py
Правило именования: файлы начинаются с «test_», функции внутри тоже. Иначе они просто не будут найдены.
Первый тест
from app.utils import shorten
def test_returns_text_unchanged_when_short():
assert shorten("Привет", 10) == "Привет"
Запуск из корня проекта:
pytest
Или подробно, с показом каждого теста:
pytest -v
Проверка исключений
Часто надо убедиться, что функция ругается на плохие данные:
import pytest
def test_raises_on_negative_limit():
with pytest.raises(ValueError):
shorten("текст", -1)
Один набор данных, много случаев
Вместо пяти почти одинаковых тестов — один с параметрами:
@pytest.mark.parametrize(
"text,limit,expected",
[
("привет", 10, "привет"),
("длинный текст", 5, "длинн…"),
("", 5, ""),
],
)
def test_shorten(text, limit, expected):
assert shorten(text, limit) == expected
Каждая строка становится отдельным тестом. Если упадёт один случай, вы увидите, какой именно.
Подготовка данных
Когда для теста нужно что-то создать заранее, это выносят в отдельную заготовку:
@pytest.fixture
def sample_notes():
return [
{"id": 1, "title": "Первая"},
{"id": 2, "title": "Вторая"},
]
def test_finds_by_id(sample_notes):
assert find_note(sample_notes, 2)["title"] == "Вторая"
Заготовка выполняется перед каждым тестом, который её запросил. Это избавляет от копирования подготовки в каждый тест.
Тесты для сервиса
Если у вас веб-сервис, его можно проверять без запуска настоящего сервера — фреймворки дают для этого тестовый клиент:
def test_notes_endpoint_returns_list(client):
response = client.get("/notes")
assert response.status_code == 200
assert isinstance(response.json(), list)
Проверяйте не только успешный случай, но и коды ошибок: что вернётся при отсутствующей записи и при неверных данных.
Полезные ключи запуска
pytest tests/test_utils.py только один файл
pytest -k "shorten" только тесты с этим словом в имени
pytest -x остановиться на первом падении
pytest --lf перезапустить только упавшие в прошлый раз
Последние два экономят много времени при починке.
Что делать, когда тест падает
Читайте вывод целиком. Показывает ожидаемое и полученное — обычно причина видна сразу.
Не правьте тест, чтобы он проходил. Сначала разберитесь, кто неправ: код или тест. Подгонка теста под неверный код — самый вредный из всех приёмов.
Изолируйте. Запустите один упавший тест отдельно. Если по отдельности проходит, а вместе нет — тесты влияют друг на друга через общее состояние. Это отдельная и частая проблема.
Что делает тесты полезными
Независимость: каждый тест должен работать сам по себе и в любом порядке. Если тесты зависят от порядка запуска, они рано или поздно начнут падать случайным образом, и им перестанут верить.
Хватит читать — пора делать
На CohortX можно найти команду под пет-проект и получить тот самый опыт, о котором спрашивают на собеседовании.
Похожие статьи
- First tests in Python: a practical introductionInstalling, where files go, writing assertions and fixtures, running them, and what to do when they fail.
- FastAPI: your first service in an eveningWhat a service for programs is, how to write your first one in an evening, and why automatic documentation saves time.
- FastAPI: первый сервис за вечерЧто такое сервис для программ, как написать первый за вечер и почему автоматическая документация экономит время.