Тестирование Python
Как устроены фикстуры pytest и их scope?
Фикстура готовит данные или ресурсы для теста. Её объявляют через @pytest.fixture, а тест запрашивает её по имени параметра. Фикстуры могут запрашивать другие фикстуры таким же способом.
scope задаёт время жизни фикстуры: function по умолчанию действует для одного теста, class для класса, module для модуля, package для пакета, session для всего прогона. Широкий scope позволяет переиспользовать ресурс, но общее изменяемое состояние может связать тесты друг с другом.
В фикстуре с yield подготовка выполняется до него, а очистка после него, когда заканчивается scope. Очистка выполняется и при падении теста, если фикстура дошла до yield.
import sqlite3
import pytest
@pytest.fixture
def db():
connection = sqlite3.connect(":memory:")
yield connection
connection.close()
def test_query(db):
assert db.execute("SELECT 1").fetchone() == (1,)
Здесь каждый тест получает отдельное соединение, которое закрывается после теста.
Ссылки для изучения
Чем pytest отличается от unittest и как выбрать?
unittest входит в стандартную библиотеку, использует классы и собственные методы assertions. pytest дает обычные assert, мощные фикстуры, параметризацию и большую экосистему плагинов; он также умеет запускать многие тесты unittest. Для нового проекта чаще удобнее pytest. Существующий стабильный набор не стоит переписывать без измеримой выгоды: фреймворки можно применять совместно и мигрировать постепенно. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Когда Mock помогает, а когда делает тест хрупким?
Mock полезен на границе с дорогой или нестабильной зависимостью: сетью, часами, внешним клиентом. Он позволяет воспроизвести отказ и проверить важное взаимодействие. Патчить нужно имя там, где его использует тестируемый модуль. Тест становится хрупким, когда проверяет внутренние вызовы вместо результата или воспроизводит реализацию реального сервиса. Контракт границы подтверждают интеграционными тестами, а autospec помогает ловить неверные сигнатуры. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Что измеряет test coverage и чего он не доказывает?
Coverage показывает, какие строки и, при branch coverage, ветви исполнялись тестами. coverage.py или pytest-cov помогают найти непройденные пути и отслеживать регресс порога. Высокий процент не доказывает правильность: тест может выполнить строку без полезного assertion, не проверить границы данных и пропустить ошибочный сценарий. Метрику используют как карту пробелов, а не как самостоятельную цель качества. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Как параметризовать тест в pytest?
В pytest используют @pytest.mark.parametrize('input,expected', [...]); каждый набор становится отдельным запуском теста. Понятные id упрощают отчет, а таблица хорошо подходит одному поведению с разными входами и ожиданиями. Если случаи требуют разной подготовки, разных assertions или объясняют разные правила, их лучше разделить: слишком широкая параметризация прячет смысл и усложняет диагностику. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Как использовать return_value, side_effect и autospec у Mock?
return_value задает обычный результат mock-вызова. side_effect может быть функцией, последовательностью результатов или исключением. assert_called_once_with проверяет важный контракт вызова. spec ограничивает доступ известными атрибутами, а autospec дополнительно учитывает сигнатуры. patch заменяет имя в модуле-потребителе, а не обязательно в модуле, где объект определен. Эти средства не заменяют проверку реальной интеграции. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Что показывает пирамида тестирования?
Пирамида тестирования показывает экономику набора: быстрых локальных тестов обычно много, интеграционных меньше, а сквозных сценариев еще меньше, потому что они медленнее и сложнее диагностируются. Это ориентир, а не требование процентов. Уровни дополняют друг друга: unit-тест проверяет правило, интеграционный подтверждает контракт с БД или сервисом, а end-to-end защищает ключевой пользовательский путь. Хороший тест проверяет наблюдаемое поведение и сохраняет понятную причину падения при изменении реализации.
Ссылки для изучения
Примеры хороших ответов из реальных собеседований
- Интервью Senior Python Developer · 52:40–55:48Собеседование · Ответ кандидата
Кандидат последовательно описывает широкое основание из unit-тестов, затем сценарные и интеграционные тесты и узкий верх из end-to-end проверок поведения пользователя.







