- Add Model Mixins: TimestampMixin, SoftDeleteMixin, AuditMixin, etc. - Add Base Services: BaseService, BulkOperationsMixin, QueryOptimizerMixin - Add Base ViewSets with bulk operations - Add BackgroundJob model for Celery task tracking - Add BaseAppCommand for management commands - Add permissions, pagination, filters, cache, logging - Migrate tests to factory_boy + faker - Add CHANGELOG.md - 297 tests passing
368 lines
12 KiB
Markdown
368 lines
12 KiB
Markdown
# Тесты для mostovik-backend
|
||
|
||
Этот документ описывает организацию и запуск тестов в проекте mostovik-backend.
|
||
|
||
## 📁 Структура тестов
|
||
|
||
```
|
||
tests/
|
||
├── __init__.py # Корневой пакет тестов
|
||
├── conftest.py # Конфигурация pytest и общие фикстуры
|
||
├── README.md # Этот файл
|
||
└── apps/ # Тесты для Django приложений
|
||
├── __init__.py
|
||
└── user/ # Тесты для приложения user
|
||
├── __init__.py
|
||
├── factories.py # Фабрики для создания тестовых данных
|
||
├── test_models.py # Тесты моделей
|
||
├── test_serializers.py # Тесты сериализаторов
|
||
├── test_services.py # Тесты сервисного слоя
|
||
└── test_views.py # Тесты представлений (API views)
|
||
```
|
||
|
||
## 🚀 Запуск тестов
|
||
|
||
### Быстрый старт
|
||
|
||
```bash
|
||
# Запуск всех тестов (рекомендуемый способ)
|
||
make test
|
||
|
||
# Запуск конкретных тестов
|
||
make test TARGET=user # Все тесты user app
|
||
make test TARGET=models # Только тесты моделей
|
||
make test TARGET=views # Только тесты представлений
|
||
|
||
# Или напрямую через скрипт
|
||
python run_tests_simple.py
|
||
python run_tests_simple.py user
|
||
```
|
||
|
||
### Различные способы запуска
|
||
|
||
#### 1. Через универсальную команду make test (рекомендуется)
|
||
|
||
```bash
|
||
# Все тесты
|
||
make test
|
||
|
||
# Конкретные группы тестов
|
||
make test TARGET=user # Все тесты user app
|
||
make test TARGET=models # Тесты моделей
|
||
make test TARGET=views # Тесты представлений
|
||
make test TARGET=serializers # Тесты сериализаторов
|
||
make test TARGET=services # Тесты сервисов
|
||
|
||
# Можно также использовать полные имена
|
||
make test TARGET=test_models # То же что и models
|
||
make test TARGET=test_views # То же что и views
|
||
```
|
||
|
||
#### 2. Через улучшенный Django runner
|
||
|
||
```bash
|
||
# Все тесты
|
||
python run_tests_simple.py
|
||
|
||
# Конкретное приложение
|
||
python run_tests_simple.py user
|
||
|
||
# Конкретные группы тестов
|
||
python run_tests_simple.py models
|
||
python run_tests_simple.py views
|
||
python run_tests_simple.py serializers
|
||
python run_tests_simple.py services
|
||
|
||
# Полные имена файлов
|
||
python run_tests_simple.py test_models
|
||
python run_tests_simple.py test_views
|
||
```
|
||
|
||
#### 3. Через стандартный Django test runner
|
||
|
||
```bash
|
||
# Все тесты
|
||
python run_tests.py
|
||
|
||
# Конкретное приложение
|
||
python run_tests.py test tests.apps.user
|
||
|
||
# Конкретный класс тестов
|
||
python run_tests.py test tests.apps.user.test_models.UserModelTest
|
||
```
|
||
|
||
#### 4. Через pytest (возможны проблемы с pdbpp)
|
||
|
||
```bash
|
||
# Через скрипт-обертку
|
||
python run_pytest.py
|
||
|
||
# Или напрямую, если настроен PYTHONPATH
|
||
export PYTHONPATH=src:$PYTHONPATH
|
||
export DJANGO_SETTINGS_MODULE=config.settings.test
|
||
pytest tests/
|
||
```
|
||
|
||
## 🔧 Конфигурация
|
||
|
||
### Настройки тестов
|
||
|
||
Тесты используют специальные настройки Django из `src/config/settings/test.py`:
|
||
|
||
- **База данных**: SQLite в памяти для быстрого выполнения
|
||
- **Кэш**: Local memory cache вместо Redis
|
||
- **Email**: Локальный backend для тестирования
|
||
- **Celery**: Синхронное выполнение задач
|
||
- **Миграции**: Отключены для ускорения
|
||
- **Логирование**: Отключено
|
||
|
||
### Pytest конфигурация
|
||
|
||
Основные настройки в `pytest.ini`:
|
||
|
||
- Автоматическое обнаружение Django настроек
|
||
- Переиспользование тестовой базы данных
|
||
- Отчеты о покрытии кода
|
||
- Фильтрация предупреждений
|
||
|
||
### Полезные опции pytest
|
||
|
||
```bash
|
||
# Подробная информация (автоматически включена)
|
||
make test TARGET=models
|
||
|
||
# Запуск конкретного файла напрямую
|
||
python run_tests_simple.py test_models
|
||
|
||
# Все тесты с подробным выводом
|
||
python run_tests_simple.py
|
||
```
|
||
|
||
## 🏭 Фабрики тестовых данных
|
||
|
||
### UserFactory
|
||
|
||
```python
|
||
from tests.apps.user.factories import UserFactory
|
||
|
||
# Создание обычного пользователя
|
||
user = UserFactory.create_user()
|
||
|
||
# Создание пользователя с конкретными данными
|
||
user = UserFactory.create_user(
|
||
email="test@example.com",
|
||
username="testuser"
|
||
)
|
||
|
||
# Создание суперпользователя
|
||
admin = UserFactory.create_superuser()
|
||
```
|
||
|
||
### ProfileFactory
|
||
|
||
```python
|
||
from tests.apps.user.factories import ProfileFactory
|
||
|
||
# Создание профиля с новым пользователем
|
||
profile = ProfileFactory.create_profile()
|
||
|
||
# Создание профиля для существующего пользователя
|
||
profile = ProfileFactory.create_profile(
|
||
user=existing_user,
|
||
first_name="John",
|
||
last_name="Doe"
|
||
)
|
||
```
|
||
|
||
## 🧪 Фикстуры pytest
|
||
|
||
Доступные фикстуры в `tests/conftest.py`:
|
||
|
||
```python
|
||
def test_example(test_user, authenticated_api_client):
|
||
"""Пример использования фикстур"""
|
||
# test_user - готовый тестовый пользователь
|
||
# authenticated_api_client - API клиент с авторизацией
|
||
response = authenticated_api_client.get('/api/user/profile/')
|
||
assert response.status_code == 200
|
||
```
|
||
|
||
### Список фикстур
|
||
|
||
- `api_client` - DRF APIClient
|
||
- `user_factory` - Фабрика пользователей
|
||
- `profile_factory` - Фабрика профилей
|
||
- `test_user` - Готовый тестовый пользователь
|
||
- `test_superuser` - Готовый суперпользователь
|
||
- `test_profile` - Готовый профиль
|
||
- `authenticated_api_client` - Авторизованный API клиент
|
||
- `admin_api_client` - API клиент с админскими правами
|
||
|
||
## 📊 Маркеры тестов
|
||
|
||
Используйте маркеры для категоризации тестов:
|
||
|
||
```python
|
||
import pytest
|
||
|
||
@pytest.mark.unit
|
||
def test_user_model():
|
||
"""Юнит тест модели"""
|
||
pass
|
||
|
||
@pytest.mark.integration
|
||
def test_user_registration_flow():
|
||
"""Интеграционный тест"""
|
||
pass
|
||
|
||
@pytest.mark.slow
|
||
def test_heavy_operation():
|
||
"""Медленный тест"""
|
||
pass
|
||
```
|
||
|
||
Запуск по маркерам:
|
||
|
||
```bash
|
||
# Только юнит тесты
|
||
python run_pytest.py -m "unit"
|
||
|
||
# Исключить медленные тесты
|
||
python run_pytest.py -m "not slow"
|
||
|
||
# Тесты моделей
|
||
python run_pytest.py -m "models"
|
||
```
|
||
|
||
## 🔍 Отладка тестов
|
||
|
||
### Просмотр вывода
|
||
|
||
```bash
|
||
# Показать print statements
|
||
python run_pytest.py -s
|
||
|
||
# Подробные ошибки
|
||
python run_pytest.py --tb=long
|
||
|
||
# Показать локальные переменные при ошибке
|
||
python run_pytest.py --tb=long --showlocals
|
||
```
|
||
|
||
### Использование pdb
|
||
|
||
```python
|
||
def test_something():
|
||
import pdb; pdb.set_trace()
|
||
# ваш код тестирования
|
||
```
|
||
|
||
```bash
|
||
# Запуск с автоматическим pdb при ошибках
|
||
python run_pytest.py --pdb
|
||
```
|
||
|
||
## 📈 Покрытие кода
|
||
|
||
### Генерация отчета
|
||
|
||
```bash
|
||
# HTML отчет
|
||
make test-coverage
|
||
|
||
# Или напрямую
|
||
python run_pytest.py --cov=src --cov-report=html:htmlcov
|
||
|
||
# Открыть отчет в браузере
|
||
open htmlcov/index.html
|
||
```
|
||
|
||
### Просмотр в терминале
|
||
|
||
```bash
|
||
python run_pytest.py --cov=src --cov-report=term-missing
|
||
```
|
||
|
||
## 🔧 Добавление новых тестов
|
||
|
||
### Создание нового файла тестов
|
||
|
||
1. Создайте файл в соответствующей папке: `tests/apps/{app_name}/test_{module}.py`
|
||
2. Импортируйте необходимые зависимости
|
||
3. Создайте классы тестов, наследуя от `TestCase` или используя функции pytest
|
||
|
||
### Пример структуры теста
|
||
|
||
```python
|
||
"""Tests for new module"""
|
||
|
||
from django.test import TestCase
|
||
from tests.apps.user.factories import UserFactory
|
||
|
||
|
||
class NewModuleTest(TestCase):
|
||
"""Tests for NewModule"""
|
||
|
||
def setUp(self):
|
||
"""Подготовка данных для тестов"""
|
||
self.user = UserFactory.create_user()
|
||
|
||
def test_something(self):
|
||
"""Test description"""
|
||
# Arrange
|
||
expected_value = "test"
|
||
|
||
# Act
|
||
result = some_function()
|
||
|
||
# Assert
|
||
self.assertEqual(result, expected_value)
|
||
```
|
||
|
||
## 🚨 Решение проблем
|
||
|
||
### Частые ошибки
|
||
|
||
1. **Ошибка импорта**: Проверьте, что `PYTHONPATH` включает папку `src`
|
||
2. **База данных**: Убедитесь, что используются тестовые настройки
|
||
3. **Миграции**: В тестах миграции отключены, но модели должны быть синхронизированы
|
||
|
||
### Очистка тестовых данных
|
||
|
||
```bash
|
||
# Очистка кеша и временных файлов
|
||
make clean
|
||
|
||
# Пересоздание тестовой базы данных
|
||
rm -f test_db.sqlite3
|
||
python run_pytest.py --create-db
|
||
```
|
||
|
||
## 📚 Полезные ссылки
|
||
|
||
- [Django Testing Documentation](https://docs.djangoproject.com/en/3.2/topics/testing/)
|
||
- [Pytest Documentation](https://docs.pytest.org/)
|
||
- [pytest-django](https://pytest-django.readthedocs.io/)
|
||
- [DRF Testing](https://www.django-rest-framework.org/api-guide/testing/)
|
||
- [Factory Boy](https://factoryboy.readthedocs.io/)
|
||
|
||
## 🚀 Быстрая справка команд
|
||
|
||
```bash
|
||
# Главная команда - make test с опциональным TARGET
|
||
make test # Все тесты
|
||
make test TARGET=user # User app (77 тестов)
|
||
make test TARGET=models # Модели (16 тестов)
|
||
make test TARGET=views # Представления (20 тестов)
|
||
make test TARGET=serializers # Сериализаторы (22 теста)
|
||
make test TARGET=services # Сервисы (18 тестов)
|
||
```
|
||
|
||
## 🤝 Рекомендации
|
||
|
||
1. **Используйте make test** - это основная и самая удобная команда
|
||
2. **Именование**: Используйте описательные имена для тестов
|
||
3. **Изоляция**: Каждый тест должен быть независимым
|
||
4. **Покрытие**: Стремитесь к покрытию не менее 80%
|
||
5. **Быстрота**: Избегайте медленных операций в юнит тестах
|
||
6. **Читаемость**: Тесты должны быть понятными и хорошо документированными |