Files
state-corp-backend/run_tests.py
Aleksandr Meshchriakov e9d7f24aaa
Some checks failed
CI/CD Pipeline / Run Tests (push) Failing after 0s
CI/CD Pipeline / Code Quality Checks (push) Failing after 1m43s
CI/CD Pipeline / Build Docker Images (push) Has been skipped
CI/CD Pipeline / Push to Gitea Registry (push) Has been skipped
first commit
2026-01-21 12:07:35 +01:00

269 lines
8.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python
"""
Простой скрипт для запуска тестов, обходящий проблемы с pytest и pdbpp
Использует стандартный Django test runner с улучшенными возможностями
Поддерживает coverage и дополнительные опции
"""
import os
import sys
from io import StringIO
import argparse
import django
def setup_django():
"""Настройка Django окружения"""
# Монкипатчим проблематичные модули
sys.modules["ipdb"] = type("MockModule", (), {"__getattr__": lambda s, n: None})()
# Добавляем src в PYTHONPATH
src_path = os.path.join(os.path.dirname(__file__), "src")
if src_path not in sys.path:
sys.path.insert(0, src_path)
# Устанавливаем настройки Django (принудительно для тестов)
os.environ["DJANGO_SETTINGS_MODULE"] = "config.settings.test"
# Инициализируем Django
django.setup()
def run_tests_with_args(test_args, options):
"""Запуск тестов с заданными аргументами"""
from django.conf import settings
from django.test.utils import get_runner
# Получаем test runner
TestRunner = get_runner(settings)
# Настройки для test runner
runner_kwargs = {
"verbosity": options.verbose,
"interactive": False,
"keepdb": options.keepdb,
"failfast": options.failfast,
}
# Добавляем parallel если указано
if options.parallel:
runner_kwargs["parallel"] = options.parallel
test_runner = TestRunner(**runner_kwargs)
# Запускаем тесты
failures = test_runner.run_tests(test_args)
return failures
def parse_arguments():
"""Парсинг аргументов командной строки"""
parser = argparse.ArgumentParser(description="Запуск Django тестов с дополнительными возможностями")
parser.add_argument(
"targets",
nargs="*",
help="Цели тестирования (по умолчанию: все тесты)",
default=["tests"]
)
parser.add_argument(
"--coverage", "--cov",
action="store_true",
help="Запуск тестов с измерением покрытия кода"
)
parser.add_argument(
"--fast",
action="store_true",
help="Запуск только быстрых тестов (исключает медленные)"
)
parser.add_argument(
"--failfast",
action="store_true",
help="Остановка при первой ошибке"
)
parser.add_argument(
"--verbose", "-v",
action="count",
default=2,
help="Уровень детализации вывода"
)
parser.add_argument(
"--keepdb",
action="store_true",
help="Сохранить тестовую базу данных"
)
parser.add_argument(
"--parallel",
type=int,
metavar="N",
help="Запуск тестов в N параллельных процессах"
)
args = parser.parse_args()
# Преобразуем пути для удобства использования
test_targets = []
for target in args.targets:
# Преобразование путей файлов в модули Django
if target.endswith(".py"):
# Убираем расширение .py
target = target[:-3]
# Заменяем слеши на точки для модульных путей
if "/" in target:
target = target.replace("/", ".")
# Добавляем префикс tests если его нет
if not target.startswith("tests"):
if target == "user":
# Если просто "user", запускаем все тесты user app
target = "tests.apps.user"
elif target in ["models", "views", "serializers", "services"]:
# Если это простые ключевые слова, добавляем test_ префикс
target = f"tests.apps.user.test_{target}"
elif (
"test_" in target
or "models" in target
or "views" in target
or "serializers" in target
or "services" in target
):
# Если это конкретный файл тестов с префиксом или содержит ключевые слова
if not target.startswith("test_"):
target = f"tests.apps.user.test_{target}"
else:
target = f"tests.apps.user.{target}"
else:
# Общий случай
target = f"tests.{target}"
test_targets.append(target)
args.targets = test_targets if test_targets else ["tests"]
return args
def print_test_info(test_targets, options):
"""Вывод информации о запуске тестов"""
print("🧪 Запуск тестов (Django test runner)...")
if test_targets == ["tests"]:
print("📁 Цель: Все тесты в проекте")
else:
print(f"📁 Цели: {', '.join(test_targets)}")
print(f"⚙️ Настройки Django: {os.environ.get('DJANGO_SETTINGS_MODULE')}")
print(f"📦 Путь к исходникам: {os.path.join(os.path.dirname(__file__), 'src')}")
# Дополнительные опции
options_info = []
if options.coverage:
options_info.append("📊 Измерение покрытия")
if options.fast:
options_info.append("🚀 Только быстрые тесты")
if options.failfast:
options_info.append("❌ Остановка при первой ошибке")
if options.keepdb:
options_info.append("💾 Сохранение тестовой БД")
if options.parallel:
options_info.append(f"⚡ Параллельность: {options.parallel}")
if options_info:
print("🔧 Опции:", " | ".join(options_info))
print("-" * 60)
def setup_coverage():
"""Настройка coverage"""
try:
import coverage
cov = coverage.Coverage(config_file="pyproject.toml")
cov.start()
return cov
except ImportError:
print("⚠️ Модуль coverage не установлен. Измерение покрытия недоступно.")
return None
def finalize_coverage(cov):
"""Завершение измерения покрытия"""
if cov:
cov.stop()
cov.save()
print("\n📊 Отчет о покрытии кода:")
print("-" * 40)
cov.report()
# Создание HTML отчета
try:
cov.html_report()
print("\n📄 HTML отчет создан в директории: htmlcov/")
except Exception as e:
print(f"⚠️ Не удалось создать HTML отчет: {e}")
def main():
"""Основная функция"""
cov = None
try:
# Парсинг аргументов
options = parse_arguments()
# Настройка coverage если нужно
if options.coverage:
cov = setup_coverage()
# Настройка Django
setup_django()
# Настройка фильтрации тестов
if options.fast:
os.environ["PYTEST_CURRENT_TEST_FILTER"] = "not slow"
# Вывод информации
print_test_info(options.targets, options)
# Запуск тестов
failures = run_tests_with_args(options.targets, options)
# Завершение coverage
if cov:
finalize_coverage(cov)
# Результат
if failures:
print(f"\n❌ Тесты завершились с ошибками: {failures} неудачных тестов")
sys.exit(1)
else:
print(f"\nВсе тесты прошли успешно!")
if cov:
print("📊 Отчет о покрытии сохранен")
sys.exit(0)
except KeyboardInterrupt:
print("\n❌ Тесты прерваны пользователем")
if cov:
cov.stop()
sys.exit(1)
except Exception as e:
print(f"\n❌ Ошибка при запуске тестов: {e}")
if cov:
cov.stop()
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()