Эффективная разработка на Python: VS Code + pytest + GitHub Copilot

Курс о том, как настроить VS Code для Python-разработки, писать и запускать тесты с pytest и ускорять работу с помощью GitHub Copilot. Разберём практический рабочий процесс: от окружения и отладки до покрытия, фикстур и качественного использования подсказок ИИ.

1. Настройка VS Code для Python: окружения, линтеры, форматирование

Настройка VS Code для Python: окружения, линтеры, форматирование

Эта статья открывает курс «Эффективная разработка на Python: VS Code + pytest + GitHub Copilot». Наша цель — сделать так, чтобы VS Code:

  • всегда запускал правильный Python из правильного окружения;
  • подсвечивал проблемы в коде (линтинг) до запуска;
  • автоматически форматировал код единообразно (форматирование).
  • В следующих статьях мы добавим тестирование через pytest и ускорим работу с GitHub Copilot. Но фундамент — это окружение, линтеры и форматирование.

    Что установим и почему

    Минимальный набор инструментов, который хорошо работает вместе:

  • Python (желательно 3.11+)
  • VS Code
  • Расширение Python для VS Code
  • Ruff как линтер и форматтер (быстро, покрывает много правил)
  • (Опционально) mypy для статической типизации
  • Ссылки на официальные источники:

  • Документация VS Code по Python
  • Репозиторий расширения Python для VS Code
  • Документация Ruff
  • Документация mypy
  • PEP 8
  • EditorConfig
  • Подготовка проекта: структура и окружение

    Правило: один проект — одно окружение. Так вы избегаете ситуации, когда VS Code «видит» одни пакеты, терминал — другие, а тесты — третьи.

    Варианты окружений

    Чаще всего используют:

    | Вариант | Когда выбирать | Плюсы | Минусы | |---|---|---|---| | venv | большинство проектов | встроен в Python, простой | зависимости в requirements.txt нужно вести аккуратно | | Poetry | если нужен удобный менеджмент зависимостей | фиксирует версии, управляет окружениями | нужно освоить команды Poetry | | Conda | если много научных/бинарных пакетов | удобно для ML/DS | отдельная экосистема, может усложнять команды |

    В рамках этой статьи будем опираться на venv, потому что он универсален и достаточно прост.

    Создаём окружение venv

    Откройте терминал в корне проекта и выполните:

    Активация:

    Проверка, что активирован именно нужный Python:

    Подключаем VS Code к нужному интерпретатору

    Устанавливаем расширение Python

    Установите расширение Python (издатель Microsoft). Оно отвечает за:

  • выбор интерпретатора;
  • запуск/отладку;
  • интеграцию линтеров и форматтеров;
  • подсказки и анализ кода.
  • Выбираем интерпретатор проекта

  • Откройте палитру команд: Ctrl+Shift+P (Windows/Linux) или Cmd+Shift+P (macOS)
  • Выполните команду Python: Select Interpreter
  • Выберите интерпретатор из .venv
  • Если .venv не находится автоматически:

  • убедитесь, что папка .venv лежит в корне workspace;
  • перезапустите окно VS Code командой Developer: Reload Window.
  • Линтинг и форматирование: в чём разница

  • Линтер ищет потенциальные ошибки, плохие практики и нарушения стиля (например, неиспользуемые импорты).
  • Форматтер приводит код к единому виду (отступы, переносы строк, кавычки — в зависимости от правил инструмента).
  • Важно: форматирование помогает договориться о стиле в команде, а линтинг — быстрее находить ошибки.

    !Как работает автоматическое форматирование и линтинг при сохранении файла

    Устанавливаем Ruff и (опционально) mypy

    Установим инструменты в проектное окружение:

    Проверка:

    Настраиваем Ruff через pyproject.toml

    Хорошая практика — хранить настройки инструментов в pyproject.toml в корне проекта.

    Создайте pyproject.toml:

    Что здесь важно:

  • line-length: максимальная длина строки (часто 88 — привычное значение в экосистеме Python).
  • target-version: под какую версию Python ориентироваться при проверках.
  • select: набор групп правил. В примере:
  • - E, F — базовые ошибки стиля и реальные ошибки (часто совпадает с тем, что ожидают по PEP 8 и pyflakes-проверкам) - I — порядок импортов - B — дополнительные проверки (bugbear) - UP — рекомендации по современному синтаксису Python

    Полный список правил и групп — в документации Ruff: Ruff Rules.

    Настраиваем VS Code: форматирование при сохранении и линтинг

    Лучше фиксировать настройки на уровне проекта, чтобы у всей команды было одинаково.

    Создайте файл .vscode/settings.json:

    Пояснения:

  • editor.formatOnSave: включает форматирование при сохранении.
  • editor.defaultFormatter: выбираем Ruff как форматтер для Python-файлов.
  • ruff.lint.enable и ruff.format.enable: включаем линтинг и форматирование Ruff.
  • python.analysis.typeCheckingMode: базовая проверка типов силами анализатора VS Code. Позже в курсе мы обсудим, когда и почему стоит включать более строгие режимы.
  • Важно про путь интерпретатора:

  • На Windows путь будет другим, например .venv\\Scripts\\python.exe.
  • Если вы работаете в команде с разными ОС, часто удобнее не фиксировать python.defaultInterpreterPath, а полагаться на Python: Select Interpreter. Но тогда важно договориться, что окружение всегда называется одинаково (например, .venv).
  • Документация по настройкам VS Code: VS Code User and Workspace Settings.

    Быстрая проверка: всё ли работает

    Создайте файл example.py:

    Ожидаемое поведение:

  • Ruff подсветит проблему с импортами (они в одной строке и не используются).
  • При сохранении файла форматирование приведёт код к единому стилю (в том числе переносы строк и пробелы).
  • Можно также запустить проверки вручную в терминале:

    Настраиваем единый стиль во всех редакторах через EditorConfig

    Если в команде кто-то использует другой редактор, полезно добавить .editorconfig:

    Что это даёт:

  • одинаковые переносы строк и отступы;
  • меньше «шумных» изменений в Git из-за пробелов и конца файла.
  • Типичные проблемы и решения

    VS Code не видит пакеты, которые установлены в терминале

    Причина почти всегда одна: VS Code использует другой интерпретатор.

    Проверьте:

  • в VS Code выбран интерпретатор из .venv (Python: Select Interpreter)
  • в терминале активировано то же окружение
  • Ruff не форматирует файл

    Проверьте:

  • установлен ли Ruff в окружение (ruff --version)
  • включён ли Ruff как форматтер в .vscode/settings.json
  • установлен ли VS Code extension Ruff (обычно идентификатор форматтера charliermarsh.ruff)
  • Конфликты форматирования

    Не включайте одновременно несколько форматтеров для Python (например, Black и Ruff Format) в режиме format on save. Выберите один инструмент как источник истины.

    Итог

    После этой настройки у вас есть базовая производственная среда разработки:

  • проектное окружение .venv и выбранный интерпретатор в VS Code;
  • единый стиль кода через Ruff Format;
  • быстрый линтинг Ruff прямо в редакторе;
  • (опционально) базовая проверка типов.
  • В следующей статье мы добавим тестирование через pytest и научим VS Code удобно запускать тесты, смотреть отчёты и быстрее находить причины падений.

    2. Основы pytest: структура тестов, assert, параметры и маркеры

    Основы pytest: структура тестов, assert, параметры и маркеры

    Эта статья продолжает курс «Эффективная разработка на Python: VS Code + pytest + GitHub Copilot». В предыдущей части мы настроили VS Code, окружение и Ruff, чтобы редактор помогал поддерживать качество кода. Теперь добавим второй фундамент: автоматические тесты.

    Задача этой статьи — научиться писать базовые тесты на pytest, понимать структуру тестов, уверенно использовать assert, параметризацию и маркеры, а также запускать тесты из терминала и из VS Code.

    Полезные источники:

  • Документация pytest
  • Как pytest обнаруживает тесты
  • assert в pytest
  • Параметризация тестов
  • Маркеры (markers)
  • Установка pytest и базовый запуск

    Устанавливайте pytest в то же окружение проекта, которое вы подключили к VS Code в прошлой статье:

    Проверка:

    Минимальный запуск тестов из корня проекта:

    Полезные флаги на каждый день:

  • pytest -q — более компактный вывод
  • pytest -x — остановиться на первом падении
  • pytest -k add — запустить тесты, имя которых содержит add
  • pytest -m smoke — запустить тесты с маркером smoke
  • Структура проекта и правила обнаружения тестов

    pytest автоматически находит тесты по соглашениям (конвенциям). Это важно: если вы назвали файл или функцию “не так”, тесты просто не запустятся.

    Обычно используют одну из двух структур:

  • простая структура для небольших проектов
  • src-layout для библиотек и более серьёзных приложений
  • Вариант: простая структура

    Вариант: src-layout

    Рекомендации по именованию для автообнаружения:

  • файлы тестов: test_.py или _test.py
  • функции тестов: test_*
  • классы тестов (не обязательно): Test и внутри методы test_
  • !Схема того, как pytest собирает и запускает тесты по соглашениям

    Первая функция и первый тест

    Представим, что у нас есть модуль app/calc.py:

    Тест tests/test_calc.py:

    Ключевые идеи:

  • тест — это обычная функция Python
  • pytest сам запускает её и показывает результат
  • проверка делается через assert
  • assert в pytest: что важно знать

    Почему assert, а не специальные методы

    В стандартном unittest часто используют self.assertEqual(...). В pytest принято писать простые выражения assert, потому что pytest:

  • переписывает (rewriting) assert-выражения и показывает понятные детали ошибки
  • выдаёт полезный дифф, если сравниваются строки, списки, словари
  • Пример теста, который упадёт, и pytest покажет детали:

    Проверка исключений через pytest.raises

    Если функция должна выбрасывать исключение, это тоже нужно тестировать.

    Пример app/calc.py:

    Тест:

    Если нужно проверить сообщение:

    Параметризация: один тест — много примеров

    Параметризация полезна, когда логика проверки одна и та же, но входные данные разные. Вместо копирования нескольких похожих тестов вы описываете набор входов.

    pytest.mark.parametrize

    Что здесь происходит:

  • строка "a,b,expected" задаёт имена параметров
  • список кортежей — это набор тест-кейсов
  • pytest создаёт отдельный запуск теста на каждый набор данных
  • Практический бонус: когда один из наборов падает, pytest показывает какой именно набор параметров был использован.

    Когда параметризация особенно полезна

  • проверки граничных значений
  • таблицы вход → ожидаемый результат
  • баг-репорты: добавили один параметр — зафиксировали воспроизведение
  • Маркеры: как управлять наборами тестов

    Маркер — это метка, которую вы навешиваете на тест, чтобы потом:

  • запускать только нужные тесты
  • пропускать определённые тесты
  • отмечать ожидаемые падения
  • Пользовательские маркеры

    Пример:

    Запуск только smoke-тестов:

    Запуск всего, кроме slow:

    skip и xfail

    Иногда тест нужно временно отключить или отметить как ожидаемо падающий.

    Пропуск:

    Ожидаемое падение:

    Смысл различия:

  • skip — тест вообще не выполняется
  • xfail — тест выполняется, но падение не считается провалом сборки (а если внезапно пройдёт, это тоже будет заметно)
  • Регистрируем маркеры в конфигурации проекта

    Если использовать свои маркеры, pytest может предупреждать о “неизвестных” маркерах. Правильная практика — зарегистрировать их в конфиге.

    Так как в прошлой статье у нас уже появился pyproject.toml, добавим настройки туда:

    Что это даёт:

  • testpaths фиксирует, где искать тесты
  • addopts задаёт параметры запуска по умолчанию
  • markers документирует маркеры и убирает предупреждения
  • Запуск pytest в VS Code

    Если вы сделали настройку окружения в прошлой статье, VS Code сможет запускать pytest без дополнительных “магических” действий.

    Обычно удобны два сценария:

  • запуск из терминала (точно повторяет поведение CI)
  • запуск из интерфейса VS Code (быстро, с навигацией по тестам)
  • Чтобы VS Code работал с pytest:

  • Откройте палитру команд Python: Configure Tests
  • Выберите pytest
  • Укажите папку tests
  • После этого появится список тестов, и вы сможете запускать отдельные тесты и видеть их статус.

    Типичные ошибки новичков

  • Тесты не находятся
  • - проверьте имена файлов test_.py и функций test_ - проверьте, что запускаете pytest из корня проекта
  • Импорты в тестах не работают
  • - убедитесь, что пакет устанавливается/виден Python (особенно при src-layout) - проверьте выбранный интерпретатор VS Code и активированное окружение
  • Случайно добавили “логическую проверку” без assert
  • - pytest не упадёт сам по себе, если вы не сделали утверждение

    Итог

    Теперь у вас есть базовая тестовая инфраструктура:

  • понятная структура tests/ и правила обнаружения
  • проверки через assert и тестирование исключений
  • параметризация для компактных и читаемых тестов
  • маркеры для управления наборами тестов и удобного запуска
  • возможность запускать pytest из терминала и VS Code
  • В следующих шагах курса это станет основой для более продуктивной разработки: быстро воспроизводить баги тестами, использовать GitHub Copilot для генерации заготовок тестов и уверенно рефакторить код под защитой тестового набора.

    3. pytest в VS Code: Test Explorer, запуск, отладка и конфигурации

    pytest в VS Code: Test Explorer, запуск, отладка и конфигурации

    Эта статья продолжает курс «Эффективная разработка на Python: VS Code + pytest + GitHub Copilot».

    В предыдущих частях мы:

  • настроили VS Code, окружение и Ruff, чтобы редактор стабильно работал с правильным интерпретатором и поддерживал стиль кода;
  • разобрали основы pytest: структуру тестов, assert, параметризацию и маркеры.
  • Теперь соберём это в удобный ежедневный рабочий процесс: как использовать pytest изнутри VS Code через Test Explorer, как запускать и отлаживать тесты, и как организовать конфигурацию так, чтобы локальный запуск совпадал с CI.

    Полезные ссылки:

  • Документация VS Code: Python testing
  • Документация pytest
  • Документация расширения Python для VS Code
  • Что даёт интеграция pytest с VS Code

    Когда VS Code настроен, вы получаете:

  • Test Explorer: дерево тестов, статусы, быстрый запуск отдельных тестов.
  • Запуск без ручного набора команд в терминале.
  • Отладку тестов с breakpoint-ами и пошаговым выполнением.
  • Удобный просмотр ошибок: где упало, почему упало, какой параметр в параметризации.
  • !Схема того, где в VS Code находятся Test Explorer, кнопки Run/Debug и где смотреть вывод

    Предусловия

    Перед настройкой тестов проверьте базовые вещи из прошлых статей:

  • VS Code использует интерпретатор из .venv.
  • pytest установлен в это же окружение.
  • Проверка в терминале VS Code:

    Если python -m pytest не находится, почти всегда причина в том, что VS Code или терминал смотрит на другое окружение.

    Включаем pytest в VS Code и настраиваем обнаружение тестов

    Настройка через интерфейс

    Самый надёжный способ первичной настройки:

  • Откройте палитру команд: Ctrl+Shift+P или Cmd+Shift+P.
  • Запустите команду Python: Configure Tests.
  • Выберите pytest.
  • Выберите папку тестов, обычно tests.
  • После этого VS Code включит тестовый адаптер и выполнит обнаружение тестов.

    Что такое обнаружение тестов

    Обнаружение тестов — это когда VS Code запускает pytest в специальном режиме, чтобы собрать список тестов и показать их в Test Explorer.

    Важно:

  • если тесты не обнаружились, это не значит, что pytest не работает вообще, но это значит, что VS Code не смог корректно их собрать;
  • чаще всего проблема в корневой папке проекта, путях импорта или выбранном интерпретаторе.
  • Настройки проекта в .vscode/settings.json

    VS Code хранит часть настроек тестирования в workspace-настройках. Минимально полезный набор выглядит так:

    Пояснения:

  • python.testing.pytestEnabled: включает pytest как фреймворк тестирования.
  • python.testing.pytestArgs: аргументы, которые VS Code добавит при запуске pytest из интерфейса.
  • python.testing.autoTestDiscoverOnSaveEnabled: пересобирает дерево тестов при изменениях.
  • > Практика: держите основные опции pytest в pyproject.toml, а pytestArgs используйте только для локальных удобств, которые не должны влиять на CI.

    Test Explorer: запуск отдельных тестов и групп

    После обнаружения откройте вкладку Testing. Там вы увидите структуру:

  • проект
  • папки и файлы тестов
  • тестовые функции
  • отдельные кейсы параметризации
  • Обычно доступны действия:

  • запуск всех тестов;
  • запуск выбранного файла;
  • запуск конкретного теста;
  • запуск упавших тестов.
  • Что важно понимать про запуск из VS Code

    VS Code запускает pytest как отдельный процесс в выбранном окружении. Это означает:

  • если вы используете переменные окружения, они должны быть доступны этому процессу;
  • рабочая директория запуска должна совпадать с тем, как вы запускаете тесты в терминале или CI.
  • Чтобы не гадать, периодически сравнивайте:

  • запуск из Test Explorer;
  • запуск из терминала командой python -m pytest из корня проекта.
  • Отладка тестов в VS Code

    Отладка в тестах нужна, когда traceback недостаточно информативен или вы хотите увидеть промежуточные значения.

    Быстрый способ: Debug Test

    В Test Explorer рядом с тестом обычно доступны две команды:

  • Run Test
  • Debug Test
  • При Debug Test вы можете:

  • поставить breakpoint в коде теста или в коде приложения;
  • выполнить шаги Step Over, Step Into, Step Out;
  • смотреть переменные и стек вызовов.
  • Управление pytest через launch.json

    Иногда нужно закрепить сценарий отладки, который легко повторить: например, запускать один файл тестов с конкретными аргументами.

    Пример .vscode/launch.json:

    Пояснения:

  • module": "pytest" запускает pytest как модуль: аналог python -m pytest.
  • args задаёт параметры pytest.
  • justMyCode скрывает часть внутренностей библиотек при отладке, чтобы легче было смотреть ваш код.
  • Конфигурация pytest: где и что хранить

    Базовый принцип

  • настройки, влияющие на поведение тестов, фиксируйте в pyproject.toml;
  • настройки, влияющие только на удобство в конкретной среде разработки, допустимо хранить в .vscode/settings.json.
  • Пример pyproject.toml

    Если вы уже добавляли это в прошлой статье, убедитесь, что настройки актуальны:

    Пояснения:

  • addopts: общие опции по умолчанию, чтобы команда pytest везде работала одинаково.
  • testpaths: где pytest ищет тесты.
  • markers: регистрация маркеров, чтобы не было предупреждений и чтобы маркеры были документированы.
  • Как сочетаются addopts и pytestArgs в VS Code

  • addopts из pyproject.toml применяется всегда, когда запускается pytest.
  • python.testing.pytestArgs добавляется сверху, когда запуск идёт из VS Code.
  • Если вы положили -q и туда, и туда, вы просто получите -q -q. Обычно это не ломает запуск, но лучше избегать дублирования и держать единый источник истины в pyproject.toml.

    Переменные окружения и файлы .env

    Тестам часто нужны переменные окружения: например, режим приложения или ключи для подключения к внешним сервисам.

    Для локальной разработки удобно хранить переменные в файле и подключать его в VS Code.

    Пример .env в корне проекта:

    И настройка в .vscode/settings.json:

    Важно:

  • не коммитьте секреты в репозиторий;
  • для CI используйте секреты GitHub Actions или аналогичный механизм.
  • Типичные проблемы VS Code + pytest и быстрые решения

    Тесты не появляются в Test Explorer

    Проверьте по порядку:

  • Выбран ли правильный интерпретатор (Python: Select Interpreter).
  • Установлен ли pytest в это окружение (python -m pytest --version).
  • Соответствуют ли имена файлов и функций правилам (test_.py, test_).
  • Открыли ли вы корень проекта как workspace, а не вложенную папку.
  • Запуск из терминала работает, а из VS Code нет

    Чаще всего отличаются:

  • рабочая директория запуска;
  • переменные окружения;
  • интерпретатор.
  • Решение обычно такое:

  • запускать pytest из корня проекта;
  • явно настроить python.envFile;
  • убедиться, что VS Code использует .venv.
  • ImportError в тестах при src-layout

    Если у вас структура src/, и тесты не видят пакет, корректные варианты:

  • установить проект в editable-режиме: python -m pip install -e .;
  • или настроить пути импорта через переменные окружения, но это менее переносимо.
  • Editable-установка чаще всего лучший вариант, потому что он ближе к тому, как пакет будет работать у пользователей.

    Итог

    Теперь у вас есть связка, которая ускоряет ежедневную разработку:

  • Test Explorer для навигации и запуска тестов;
  • быстрый запуск отдельных тестов и параметризованных кейсов;
  • отладка тестов через Debug Test и через launch.json;
  • единая конфигурация pytest в pyproject.toml, чтобы локальный запуск был ближе к CI.
  • В следующих материалах курса эта инфраструктура станет базой для ускорения разработки с GitHub Copilot: генерации заготовок тестов, подсказок по фикстурам и более безопасного рефакторинга под защитой тестов.

    4. Продвинутый pytest: фикстуры, monkeypatch, coverage и отчёты

    Продвинутый pytest: фикстуры, monkeypatch, coverage и отчёты

    Эта статья продолжает курс «Эффективная разработка на Python: VS Code + pytest + GitHub Copilot». Ранее мы настроили VS Code и окружение, разобрали основы pytest и научились запускать и отлаживать тесты из Test Explorer.

    Теперь усилим тестовую практику до уровня, который обычно нужен в реальных проектах:

  • фикстуры pytest как основной механизм подготовки окружения тестов
  • monkeypatch для подмены зависимостей без сложного мокинга
  • измерение покрытия кода (coverage) и полезные отчёты
  • интеграция отчётов с CI и удобная работа из VS Code
  • Полезные ссылки:

  • pytest fixtures
  • pytest: fixture scopes
  • pytest: monkeypatch fixture
  • pytest: capturing stdout/stderr
  • pytest-cov
  • coverage.py documentation
  • Фикстуры: что это и зачем они нужны

    Фикстура в pytest — это функция (или объект), которая подготавливает состояние для теста и возвращает данные тесту. В отличие от ручной подготовки внутри каждого теста, фикстуры:

  • убирают дублирование кода
  • делают тесты короче и понятнее
  • позволяют централизованно управлять ресурсами (временные файлы, окружение, подключения)
  • дают предсказуемый порядок создания и очистки
  • Базовый пример фикстуры

    Предположим, у нас есть простая функция, которая читает режим приложения из переменной окружения.

    app/config.py:

    Тест с фикстурой, которая устанавливает окружение:

    tests/test_config.py:

    Идея: тест получает фикстуру как аргумент, а pytest сам заботится о том, чтобы фикстура выполнилась до теста.

    yield-фикстуры: setup и teardown в одном месте

    Когда нужно не только создать ресурс, но и корректно его очистить, используйте yield.

    Важно понимать:

  • код до yield — подготовка
  • значение после yield — то, что получит тест
  • код после yield — освобождение ресурсов
  • Области видимости (scope) фикстур

    Scope определяет, как часто создаётся фикстура.

  • function — на каждый тест (значение по умолчанию)
  • class — один раз на класс тестов
  • module — один раз на файл тестов
  • package — один раз на пакет тестов
  • session — один раз на весь запуск pytest
  • !Схема, как scope влияет на частоту создания фикстуры

    Пример фикстуры уровня session для условно дорогой инициализации:

    Практика: чем меньше scope, тем лучше изоляция тестов. Увеличивайте scope только когда есть явная необходимость (скорость, дорогие ресурсы).

    autouse: фикстуры, которые применяются автоматически

    Иногда нужно применить настройку ко всем тестам, не добавляя аргумент в каждую функцию.

    tests/conftest.py:

    Рекомендация: autouse=True используйте аккуратно, потому что скрытая магия усложняет понимание тестов.

    conftest.py: общие фикстуры для папки тестов

    conftest.py — специальный файл pytest для фикстур и хуков, которые будут доступны тестам в этой директории и вложенных.

    Обычно туда выносят:

  • общие фикстуры (например, client, settings, fake_clock)
  • запреты на внешние зависимости (например, запрет сети)
  • генераторы тестовых данных
  • monkeypatch: безопасная подмена зависимостей

    monkeypatch — встроенная фикстура pytest, которая умеет временно изменять окружение на время теста и гарантированно откатывать изменения после.

    Зачем это нужно:

  • подменить переменные окружения
  • подменить атрибуты и функции в модулях
  • подменить текущую директорию
  • подменить элементы словарей (например, os.environ)
  • Подмена переменных окружения

    Подмена функции в модуле

    Сделаем пример функции, зависящей от времени.

    app/time_utils.py:

    Тест: подменяем datetime.now на управляемое значение через подмену объекта datetime в модуле.

    tests/test_time_utils.py:

    Замечания:

  • мы патчим именно то место, откуда код читает зависимость (модуль app.time_utils)
  • monkeypatch сам откатит изменения после теста
  • Подмена текущей директории и работа с файлами

    pytest даёт удобную встроенную фикстуру tmp_path, которая создаёт уникальную временную директорию под каждый тест.

    Если код работает с относительными путями, можно сменить директорию:

    Полезные встроенные фикстуры pytest для практики

  • tmp_path — временная директория типа pathlib.Path
  • monkeypatch — безопасные подмены
  • capsys — перехват вывода в stdout/stderr
  • Пример capsys:

    Coverage: измеряем покрытие кода тестами

    Покрытие отвечает на вопрос: какие строки вашего кода выполнялись во время тестов. Это не гарантия качества тестов, но очень полезный индикатор:

  • видны непроверенные ветки логики
  • проще контролировать качество изменений
  • удобно в CI как минимальный порог
  • Установка и запуск pytest-cov

    Установите плагин в окружение проекта:

    Запуск с измерением покрытия для пакета app:

    Полезные варианты отчётов:

  • вывести отчёт в терминал с пропущенными строками
  • сформировать HTML-отчёт (удобно открывать в браузере)
  • По умолчанию HTML будет в папке htmlcov/, откройте htmlcov/index.html.

    Порог покрытия (fail-under)

    Чтобы сборка падала, если покрытие ниже порога:

    Рекомендация: вводите пороги постепенно. Лучше иметь реалистичный порог и повышать его, чем поставить слишком высокий и получить саботаж тестов.

    Конфигурация coverage и pytest в pyproject.toml

    Хорошая практика — фиксировать общие настройки в pyproject.toml, чтобы локальный запуск и CI были максимально одинаковыми.

    Пример (адаптируйте под свой проект):

    Пояснения:

  • branch = true включает анализ покрытия ветвлений, чтобы видеть не только строки, но и альтернативные пути
  • source = ["app"] ограничивает coverage вашим кодом, а не зависимостями
  • show_missing = true делает отчёт более практичным
  • Документация по настройке coverage в pyproject.toml есть в coverage.py: coverage.py documentation.

    Отчёты: что сохранять, чтобы было удобно в CI и при разборе падений

    JUnit XML: отчёт о тестах для CI-систем

    Многие CI-системы умеют прикреплять и визуализировать JUnit-отчёты.

    Сгенерировать XML:

    Практика:

  • сохраняйте reports/ как артефакт в CI
  • это помогает быстро увидеть список упавших тестов и историю
  • Coverage XML: отчёт покрытия для внешних систем

    Некоторым инструментам нужен XML-формат покрытия:

    HTML coverage: самый полезный отчёт для локальной работы

    Для локального анализа чаще всего удобнее HTML:

    Дальше открывайте htmlcov/index.html.

    Как связать это с VS Code и GitHub Copilot

    VS Code

    VS Code умеет запускать pytest из Test Explorer, но coverage обычно удобнее запускать отдельной командой в терминале или через отдельную конфигурацию.

    Практичный вариант: добавить задачу (task) или просто запомнить команды:

    Если вы отлаживаете конкретный тест, сначала используйте Debug Test, а coverage гоняйте уже после фикса.

    GitHub Copilot

    Copilot особенно полезен в двух местах:

  • быстро накидать скелет фикстуры и тест-кейсы для параметризации
  • предложить варианты подмен через monkeypatch и проверки побочных эффектов
  • Важно сохранять контроль качества:

  • проверяйте, что Copilot патчит правильный импорт (патчить нужно то место, где зависимость используется)
  • не принимайте «магические» фикстуры с autouse=True, если они скрывают логику теста
  • добавляйте отчёты coverage, чтобы видеть, что предложенные тесты реально исполняют нужные ветки
  • Типичные ошибки и быстрые решения

  • Фикстура не находится
  • Проверьте, что она лежит в conftest.py в правильной папке или импортируется явно
  • Monkeypatch «не сработал»
  • Скорее всего вы патчите не то место: патчить нужно ссылку, которую использует код, а не «оригинал где-то в библиотеке»
  • Coverage показывает странные файлы
  • Ограничьте измерение через --cov=app и source = ["app"] в конфиге
  • Высокое coverage, но баги всё равно пролезают
  • Покрытие не равно качеству: добавляйте проверки смысла, граничных условий и отрицательных сценариев, а не только «вызов функции без assert»
  • Итог

    Теперь ваш стек тестирования стал заметно практичнее:

  • фикстуры дают чистую архитектуру тестов и контроль жизненного цикла ресурсов
  • monkeypatch позволяет безопасно подменять окружение и зависимости
  • tmp_path и capsys закрывают частые нужды тестирования файлов и вывода
  • pytest-cov и отчёты (terminal, HTML, XML, JUnit) делают качество измеримым и удобным для CI
  • Следующий логичный шаг в развитии курса — закрепить эти практики в реальном репозитории и подключить их к автоматическим проверкам, чтобы VS Code, pytest и отчёты работали вместе так же, как на CI.

    5. GitHub Copilot для тестирования: промпты, генерация тестов и ревью качества

    GitHub Copilot для тестирования: промпты, генерация тестов и ревью качества

    Эта статья продолжает курс «Эффективная разработка на Python: VS Code + pytest + GitHub Copilot» и логически опирается на предыдущие темы:

  • мы уже настроили VS Code, окружение и Ruff, чтобы код был единообразным;
  • разобрали pytest и научились запускать и отлаживать тесты в VS Code;
  • дошли до фикстур, monkeypatch, coverage и отчётов.
  • Теперь добавим ускоритель: GitHub Copilot как помощник для тестирования. Важно: Copilot не заменяет инженерное мышление и ревью, но хорошо ускоряет рутину.

    Полезные источники:

  • Документация GitHub Copilot
  • Документация VS Code: GitHub Copilot
  • pytest documentation
  • Что Copilot реально даёт в тестировании

    Copilot особенно полезен, когда нужно быстро:

  • накидать скелет тестов под существующий код;
  • придумать набор кейсов, включая границы и ошибки;
  • сформировать фикстуры и данные;
  • подсказать, где применить parametrize, monkeypatch, tmp_path, capsys;
  • помочь с рефакторингом тестов и улучшением читаемости.
  • Copilot хуже справляется, когда:

  • нет контекста (код не открыт, нет примеров использования);
  • логика доменная и требует знания требований;
  • тесты завязаны на инфраструктуру (БД, сеть, очереди) и нужны решения по изоляции;
  • важно не просто «покрыть строки», а проверить смысл.
  • !Процесс использования Copilot для создания и проверки тестов

    Подготовка Copilot в VS Code

    В большинстве случаев достаточно:

  • установить расширение GitHub Copilot в VS Code;
  • авторизоваться в GitHub в VS Code;
  • убедиться, что проект открыт как workspace, а тесты запускаются через python -m pytest.
  • Практика из предыдущих статей остаётся ключевой: Copilot должен работать в проекте, где уже настроены pytest, структура tests/, фикстуры и конфиг в pyproject.toml.

    Как Copilot «видит» контекст

    Copilot генерирует предложения на основе контекста. Для тестов это критично.

    Чтобы повысить качество генерации:

  • держите открытым файл с кодом, который тестируете;
  • держите открытым файл с похожими тестами (пример стиля проекта);
  • используйте единые инструменты (pytest + фикстуры + Ruff), чтобы Copilot повторял паттерны.
  • Если в проекте принят подход src/-layout и editable-установка (python -m pip install -e .), Copilot обычно реже ошибается с импортами в тестах.

    Основная техника: промпт как техническое задание

    В тестировании полезно думать о промпте как о мини-ТЗ:

  • что тестируем (функция, модуль, сценарий);
  • какие требования и инварианты;
  • какие граничные случаи;
  • что нельзя делать (сеть, время, случайность, реальная файловая система);
  • какой стиль ожидается (pytest, фикстуры, параметризация, имена тестов).
  • Шаблон промпта для генерации тестов

    Ниже универсальный шаблон, который хорошо работает в Copilot Chat:

    Таблица промптов под типовые задачи

    | Задача | Промпт | Что проверить после генерации | |---|---|---| | Быстро покрыть функцию кейсами | Напиши pytest-тесты для <func>, добавь граничные значения и исключения | Есть ли смысловые проверки, а не только вызов функции | | Перевести дубли в parametrize | Перепиши эти тесты, используя pytest.mark.parametrize, сохрани читаемость | Имена параметров, читаемость таблицы кейсов | | Добавить фикстуры | Вынеси общую подготовку в fixture в conftest.py, обнови тесты | Scope фикстуры, нет ли скрытой магии через autouse без необходимости | | Убрать зависимость от времени/окружения | Сделай тесты детерминированными: monkeypatch для env/времени | Патчится ли правильное место импорта | | Улучшить диагностику падений | Добавь понятные assert и сообщения, проверь match в pytest.raises | Assert проверяют поведение, а не внутренности |

    Пример: Copilot генерирует тесты с параметризацией и исключениями

    Допустим, у нас есть модуль app/discounts.py:

    Промпт в Copilot Chat:

    Ожидаемый результат (пример того, к чему стоит привести сгенерированный код):

    Что важно в ревью такого результата:

  • параметризация покрывает нормальные сценарии без копипаста;
  • исключения проверяются через pytest.raises;
  • проверка match фиксирует смысл ошибки и помогает не пропустить регресс.
  • Пример: Copilot и monkeypatch для детерминированных тестов

    Пусть есть код, зависящий от окружения.

    app/config.py:

    Хороший промпт:

    Ожидаемый результат (пример):

    Здесь Copilot обычно силён, но всё равно проверяйте:

  • тест не зависит от реального окружения машины;
  • используется delenv(..., raising=False), чтобы тест был устойчивым.
  • Copilot для улучшения качества существующих тестов

    Copilot полезен не только для «написать с нуля», но и для итеративного улучшения.

    Улучшение читаемости и структуры

    Промпты, которые часто дают хороший эффект:

  • Сделай эти тесты более читаемыми: вынеси дубли в фикстуры, но не используй autouse
  • Переименуй тесты так, чтобы имена отражали поведение и условия
  • Замени ручные циклы на pytest.mark.parametrize
  • Усиление проверок

    Если тесты выглядят как «вызвали функцию и не упало», попросите Copilot усилить смысл:

    Дальше вы вручную проверяете, что asserts действительно фиксируют требования.

    Ревью тестов, сгенерированных Copilot: чеклист качества

    Copilot может написать тесты, которые формально запускаются, но бесполезны. Ниже практичный чеклист ревью.

    Проверка смысла теста

  • тест проверяет поведение, а не детали реализации;
  • в тесте есть понятные assert, а не только «вызов без падения»;
  • для ошибок используются pytest.raises и, при необходимости, match.
  • Изоляция и детерминизм

  • нет зависимости от текущей даты/времени, часового пояса, сети;
  • нет зависимости от порядка запуска тестов;
  • используются tmp_path и monkeypatch, а не реальные ресурсы.
  • Качество данных и кейсов

  • есть граничные значения (нули, пустые строки, минимумы/максимумы);
  • есть негативные сценарии (некорректные входы, исключения);
  • параметризация не превращается в нечитаемую «простыню».
  • Стиль проекта и поддерживаемость

  • имена тестов читаются как спецификация;
  • фикстуры имеют корректный scope;
  • нет необоснованного autouse=True;
  • тесты проходят Ruff и не плодят неиспользуемые импорты.
  • Связка с pytest в VS Code и coverage

    Идеальный рабочий цикл после генерации Copilot:

  • Запустите тесты в VS Code через Test Explorer, чтобы быстро увидеть падения.
  • Если тест падает неочевидно, используйте Debug Test.
  • Запустите coverage, чтобы убедиться, что тесты реально исполняют нужные ветки:
  • Откройте HTML-отчёт, чтобы увидеть «дыры» и попросить Copilot предложить дополнительные кейсы:
  • Хороший промпт по результатам coverage:

    Типичные ошибки при использовании Copilot в тестировании

  • Copilot генерирует мок/патч «не в том месте»
  • Причина: патчить нужно ссылку, которую использует код, а не «где-то в библиотеке». Сверяйтесь с импортами в тестируемом модуле.
  • Copilot предлагает слишком много фикстур
  • Причина: попытка «сделать красиво» может усложнить понимание. Оставляйте фикстуры только там, где есть повтор.
  • Copilot делает тесты, зависимые от окружения
  • Решение: явно требуйте monkeypatch, tmp_path, запрет сети, фиксированное время.
  • Copilot «достигает coverage», но не проверяет смысл
  • Решение: добавляйте требования к инвариантам и ожидаемым свойствам результата, а не к строкам кода.
  • Итог

    GitHub Copilot ускоряет тестирование, если использовать его правильно:

  • формулируйте промпты как мини-ТЗ с ограничениями и ожидаемым стилем pytest;
  • просите параметризацию, pytest.raises, фикстуры и monkeypatch только там, где они нужны;
  • всегда прогоняйте тесты в VS Code и проверяйте coverage;
  • делайте ревью тестов по чеклисту: смысл, детерминизм, изоляция, читаемость.
  • Так вы получаете главное: скорость разработки без потери качества и предсказуемости тестового набора.