Files
state-corp-backend/run_tests.py
Aleksandr Meshchriakov fd2adf9ab4 Refactor project structure and update configurations for State Corp backend
- Updated project description in __init__.py
- Enhanced .gitignore to exclude additional data files
- Modified User model to remove first_name and last_name fields
- Improved instance save method in services.py to include updated_at field
- Added API tokens to .env.example for external services
- Cleaned up test files for better readability
- Updated Dockerfile and docker-compose.yml for improved setup
- Revised README.md to reflect project changes and added changelog
2026-02-17 09:24:42 +01:00

266 lines
8.7 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 argparse
import os
import sys
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("\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()