Главная/Материалы/Материал

pytest-container

Запуск тестов внутри образа как стадии сборки. Используется в уроке 6.12 и в разделе 15.

Что демонстрирует

  • стадия test, не входящая в финальный образ;
  • падение тестов останавливает сборку — тесты становятся обязательными;
  • порог покрытия (fail_under = 90) проверяется там же;
  • независимая стадия lint собирается параллельно со стадией test;
  • в финальном образе нет ни pytest, ни ruff, ни тестов.

Запуск

Финальный образ — стадия test при этом не выполняется:

bash
docker build -t calc .
docker run --rm calc

Явный запуск тестов:

bash
docker build --target test -t calc:test .

Явный запуск линтера:

bash
docker build --target lint -t calc:lint .

Проверка: тесты блокируют сборку

Сломайте любой тест и убедитесь, что сборка падает:

bash
sed -i 's/assert divide(a, b) == expected/assert divide(a, b) == 999/' tests/test_core.py
docker build --target test -t calc:test . ; echo "exit code: $?"

Ожидается ненулевой код и отчёт pytest с упавшим тестом.

Верните тест:

bash
sed -i 's/assert divide(a, b) == 999/assert divide(a, b) == expected/' tests/test_core.py

Проверка: порог покрытия

Порог задан в pyproject.toml (fail_under = 90). Добавьте непокрытую функцию в src/calc/core.py и пересоберите стадию test — сборка упадёт по недобору покрытия, а не по упавшему тесту.

Проверка: финальный образ чист

bash
docker run --rm --entrypoint sh calc -c 'command -v pytest || echo "pytest отсутствует"'
docker run --rm --entrypoint sh calc -c 'ls /app/tests 2>/dev/null || echo "тестов нет"'
docker run --rm --entrypoint id calc -u

Параллельность стадий

Стадии lint и test независимы — BuildKit собирает их одновременно:

bash
docker build --no-cache --target lint -t calc:lint . &
docker build --no-cache --target test -t calc:test . &
wait

Локальный запуск без Docker

bash
python -m venv .venv && . .venv/bin/activate
pip install -e . -r requirements-dev.txt
pytest --cov=calc
ruff check src/

Уборка

bash
docker rmi calc calc:test calc:lint 2>/dev/null
Markdown на GitHub ↗