DevOpsБэкендPythonДругой язык

GitHub Actions для Python: запускаем тесты после каждого push

Настраиваем workflow для Python и pytest: checkout, setup-python, установка зависимостей, зелёный статус и разбор типичных ошибок YAML.

Кодик

Автор

7 мин чтения

GitHub Actions может запускать pytest на чистой виртуальной машине после каждого push и pull request. Добавим один YAML-файл, увидим зелёный check и специально сломаем тест. Разберём, откуда берётся код, где устанавливается Python и почему локальный успех ещё не гарантирует зелёный CI.

На своём ноутбуке легко забыть зависимость или запуск тестов. CI повторяет проект с нуля и фиксирует результат рядом с коммитом. В этой статье вы соберёте workflow из четырёх понятных шагов. Финальный результат можно проверить без догадок: вкладка Actions показывает job tests со статусом success, а сломанный assert делает check красным.

1Получаем код

actions/checkout переносит содержимое репозитория на runner.

2Готовим Python

setup-python выбирает версию и при необходимости включает cache pip.

3Запускаем тесты

pytest возвращает 0 при успехе и ненулевой код при падении.

Из чего состоит workflow GitHub Actions

Workflow хранится в .github/workflows/python-tests.yml. Блок on описывает события, jobs создаёт независимые задания, runs-on выбирает образ, а steps перечисляет команды по порядку. Каждый запуск получает новую среду без вашей .venv. Для GitHub Actions держите этапы раздельно: ввод, проверка, основное действие и вывод. Такой маршрут позволяет остановиться в конкретной точке, увидеть фактические данные и исправить одну причину вместо случайной перестановки строк.

ЭтапДействиеПроверяемый результат
Событиеpush или pull_request создаёт runВ Actions появляется запуск
CheckoutКод копируется на runnerФайлы проекта доступны
Окружениеsetup-python ставит Python 3.12python --version совпадает
Тестыpip ставит pytest и запускает наборJob зелёный или красный

CI повторяет только то, что описано в YAML, поэтому скрытая локальная настройка сразу становится заметной. У GitHub Actions каждый этап оставляет наблюдаемый след, поэтому следующий шаг начинается только после проверки предыдущего.

Путь commit через GitHub Actions
От входных данных до видимого результата. Статус связан с конкретным commit SHA

Не храните секреты прямо в workflow. Если проекту нужен токен, добавьте его в GitHub Actions secrets и передайте через env. Не печатайте значение в логе и не используйте секрет для pull request из недоверенного форка.

Создаём python-tests.yml

Сначала положите рабочие price.py и test_price.py из предыдущей статьи в GitHub-репозиторий. Создайте каталог .github/workflows и файл python-tests.yml. Коммит можно отправить через git add ., git commit -m "Add Python tests workflow" и git push. После push откройте вкладку Actions и конкретный run.

name: Python tests

on:
  push:
  pull_request:

permissions:
  contents: read

jobs:
  tests:
    runs-on: ubuntu-latest
    steps:
      - name: Check out repository
        uses: actions/checkout@v6

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.12"
          cache: pip

      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          pip install pytest

      - name: Run tests
        run: pytest -q
Что должно произойти после запуска
  • Push создаёт отдельный workflow run.
  • В job tests видны четыре шага и их длительность.
  • pytest печатает passed и завершает команду кодом 0.
  • Сломанный assert завершает Run tests кодом 1.

Версии actions закреплены по major-тегу, а Python задан явно. Это делает пример понятным и не привязывает его к случайной версии runner. Пример GitHub Actions специально ограничен одним пользовательским сценарием, чтобы назначение каждой строки оставалось видимым.

Локальный запуск и чистый runner
Что отличает устойчивый проект от случайного запуска. CI раскрывает скрытые локальные зависимости

Как читать job, step и лог runner

Runner получает временную виртуальную машину ubuntu-latest. Checkout скачивает конкретный commit SHA, поэтому лог относится к точному состоянию кода. setup-python добавляет выбранный интерпретатор в PATH. Каждый run выполняется в рабочем каталоге репозитория. Если команда run возвращает ненулевой код, step и job становятся failed, следующие обычные шаги не запускаются. Cache ускоряет повторную установку, но не заменяет requirements.txt: список зависимостей всё равно должен быть записан в проекте.

ЧастьЗа что отвечаетЧто проверить
onОпределяет события запускаНет лишнего schedule
permissionsОграничивает GITHUB_TOKENДля тестов достаточно contents: read
jobСоздаёт одну машинуИмя tests видно в checks
usesПодключает готовое actionУказана поддерживаемая версия
runВыполняет shell-командуКод завершения проверяется

YAML чувствителен к отступам и не использует табы. Значение on иногда интерпретируют как boolean старые парсеры, но GitHub читает его по своей схеме. Для нескольких версий Python добавьте strategy.matrix, когда библиотека действительно должна их поддерживать. Для учебного приложения одна версия проще. Не ставьте continue-on-error на тесты: он превратит красный набор в зелёный check. Если зависимостей стало больше, перенесите их в pyproject.toml и устанавливайте проект одной командой.

Зелёный badge не доказывает, что запускался нужный тест. Откройте лог Run tests и проверьте количество tests. Пустой каталог, неверный шаблон имени или команда true тоже дают зелёный job, но не защищают код.

Делаем красный check и чиним его

Отправьте зелёный workflow. Затем временно поменяйте expected в одном тесте, сделайте второй push и откройте красный лог. Найдите строку assert и значения. Верните исправление. После этого добавьте шаг python --version, чтобы увидеть среду. Создайте ветку и pull request, убедитесь, что workflow запускается и там. Последний шаг: перенесите pytest в dependency group pyproject.toml и замените ручную установку на команду проекта.

Проверка своими руками
  1. Создайте YAML только пробелами.
  2. Получите зелёный run после push.
  3. Сломайте один assert и найдите diff.
  4. Верните тест и восстановите success.
  5. Проверьте запуск на pull request.
  6. Убедитесь, что job выполняет все тесты.
Готово, если выполняются все пункты
  • Workflow запускается по двум событиям.
  • Python-версия задана явно.
  • Красный тест блокирует job.
  • Лог указывает на конкретный assert.

CI полезен только тогда, когда красный результат нельзя незаметно проигнорировать. После этой проверки измените одно правило GitHub Actions и заранее запишите ожидаемый результат. Так копирование превращается в понимание.

Четыре проверки рабочего CI
Четыре проверки перед следующим шагом. Красный тест должен останавливать job

Как развивать CI без лишней магии

Следом добавьте форматтер или линтер отдельным step, но не смешивайте его ошибку с тестами без ясного имени. Matrix нужна библиотеке с несколькими версиями Python, а приложению часто достаточно одной поддерживаемой. Деплой подключайте только после зелёных тестов и отдельного решения о среде. Для внешних pull request ограничивайте права токена. Обновляйте actions осознанно, читайте changelog major-версии и не копируйте неизвестный workflow из случайного репозитория.

Как изучить тему в Кодике

Сначала закрепите git add, commit и push, затем свяжите код завершения команды со статусом job. В Кодике сначала восстановите чистую логику без фреймворка, затем верните библиотеку и интерфейс GitHub Actions.

ШагЧто разобратьМини-проверка
1Git и GitHubОтправить отдельный commit
2Командная строкаПолучить exit code pytest
3YAMLОбъяснить отступы jobs/steps
4Окружение PythonЗадать версию и зависимости
5CI-пайплайнПоймать сломанную проверку

Пока workflow не ловит намеренно внесённый дефект, не добавляйте deploy и сложную matrix. Финальная проверка для GitHub Actions: закрыть статью, объяснить путь данных и добавить одну функцию без копирования готового блока.

Файл лежит не в .github/workflows

GitHub не увидит YAML в произвольном каталоге.

Зависимость есть только локально

Опишите установку в workflow или pyproject.toml.

Тестам разрешили continue-on-error

Уберите флаг, иначе check останется зелёным при падении.

В YAML стоят табы

Используйте пробелы и проверяйте структуру по логу workflow.

Сверяйтесь с первичной документацией. Команды и ограничения примера проверены по официальной документации GitHub Actions для Python. Если версия инструмента изменилась, официальный источник важнее старого скриншота.

Что получится в итоге

Готовый результат проекта: GitHub Actions для Python: запускаем тесты после каждого push
Каждый push проходит чистый runner, а сломанный assert меняет статус job на failed и оставляет диагностический лог.

Короткие ответы
Где хранится workflow GitHub Actions?

Workflow хранится в YAML-файле каталога .github/workflows внутри репозитория.

Почему pytest делает job красным?

При падении теста pytest возвращает ненулевой код завершения, и step получает статус failed.

Зачем нужен actions/checkout?

checkout переносит код конкретного commit на runner, чтобы команды работали с файлами проекта.

Как понять, что учебный проект GitHub Actions действительно работает?

Проверьте основной сценарий GitHub Actions, неверный ввод, повторный запуск и один граничный случай. Затем объясните путь данных своими словами.

Можно ли начать с готового кода GitHub Actions из статьи?

Да. Сначала добейтесь результата GitHub Actions, затем измените одно правило и восстановите ключевой файл без копирования.

Соедините локальный тест и автоматический check

Git закрепите в курсе Git, а Python и тестируемые функции в курсе Python. Начните с первых тестов pytest.

Перед публикацией репозитория сверяйтесь с материалом как загрузить проект на GitHub, а браузерный уровень добавьте через Playwright на Python.