13 KiB
🔍 Подробный отчет: Проблемы с тестами аутентификации
Дата: 5 января 2026
Файл: tests/api/auth/test_auth_and_registration.py
📊 Статистика
✅ 8 тестов ПРОШЛИ
❌ 11 тестов ПРОВАЛЕНЫ
━━━━━━━━━━━━━━━━━━━━━
📈 Успешность: 42%
🔴 ОСНОВНАЯ ПРОБЛЕМА
🚨 КРИТИЧЕСКОЕ НЕСООТВЕТСТВИЕ: Модель vs Сериализатор
✅ Модель Employee (models.py:162-165):
gender = models.PositiveSmallIntegerField(
"Пол", choices=GENDER_CHOICES,
default=0, # ✅ Есть дефолт
blank=True # ✅ НЕОБЯЗАТЕЛЬНОЕ
)
avatar = models.ImageField(
"Фото", upload_to="users/avatars",
blank=True, # ✅ НЕОБЯЗАТЕЛЬНОЕ
null=True # ✅ НЕОБЯЗАТЕЛЬНОЕ
)
❌ RegisterSerializer (serializers.py:29-67):
class RegisterSerializer(serializers.Serializer):
# ... другие поля ...
avatar = Base64ImageField(required=True) # ❌ ОБЯЗАТЕЛЬНОЕ (противоречие!)
gender = serializers.ChoiceField(
required=True, # ❌ ОБЯЗАТЕЛЬНОЕ (противоречие!)
choices=((1, "Мужской"), (2, "Женский")),
error_messages={
'required': 'Поле "Пол" обязательно для заполнения.',
}
)
⚠️ Проблема: Сериализатор требует поля, которые в модели необязательны. Это создает искусственные требования для API регистрации, не соответствующие структуре БД.
Обязательные поля в RegisterSerializer
Файл: backend/api/v1/employees/serializers.py (строки 29-67)
class RegisterSerializer(serializers.Serializer):
# ... другие поля ...
avatar = Base64ImageField(required=True) # ❌ ОБЯЗАТЕЛЬНОЕ
gender = serializers.ChoiceField(
required=True, # ❌ ОБЯЗАТЕЛЬНОЕ
choices=((1, "Мужской"), (2, "Женский")),
error_messages={
'required': 'Поле "Пол" обязательно для заполнения.',
}
)
Что отправляют тесты
Файл: tests/api/auth/test_auth_and_registration.py (строка 44)
def register_payload(**overrides):
data = {
"first_name": "Иван",
"last_name": "Иванов",
"phone_number": "+79990000001",
"email": "ivan@example.com",
"password": "Str0ngPass!",
"birth_date": "1990-01-01",
"telegram": "@ivan",
# ❌ НЕТ avatar
# ❌ НЕТ gender
}
return data
📝 Ошибки валидации
Все 11 проваленных тестов получают одинаковую ошибку:
[REGISTER] Validation errors: {
'avatar': [ErrorDetail(string='Ни одного файла не было отправлено.', code='required')],
'gender': [ErrorDetail(string='Поле "Пол" обязательно для заполнения.', code='required')]
}
HTTP статус: 400 Bad Request (ожидается 201 Created)
📋 Детальный список проваленных тестов
1. ❌ test_register_success_sends_email_and_user_inactive
Цель: Проверка успешной регистрации с отправкой email
Проблема: Не передает avatar и gender
2. ❌ test_register_duplicate_email_phone
Цель: Проверка дубликатов email/phone
Проблема: Не может создать первого пользователя (нет avatar, gender)
3. ❌ test_register_accepts_optional_fields
Цель: Проверка опциональных полей (patronymic, whatsapp)
Проблема: Передает gender=1, но не передает avatar
# Частичное исправление в тесте:
payload = {
...
"patronymic": "Петрович",
"gender": 1, # ✅ Есть
"whatsapp": "+79995550011",
# ❌ Нет avatar
}
4-11. ❌ Тесты верификации email и логина
Все зависят от register() функции, которая не передает обязательные поля:
test_verify_email_success_activates_usertest_verify_email_wrong_codetest_resend_email_sends_new_code_and_old_becomes_invalidtest_verify_expired_more_than_5_minutes_deletes_accounttest_login_by_email_denied_before_verifytest_login_by_email_allowed_after_verifytest_login_by_phone_allowed_after_verifytest_login_wrong_password
✅ Успешные тесты (8 штук)
Эти тесты проверяют валидацию отсутствующих полей, поэтому они ожидают 400 Bad Request:
- ✅
test_register_missing_required_field[first_name] - ✅
test_register_missing_required_field[last_name] - ✅
test_register_missing_required_field[phone_number] - ✅
test_register_missing_required_field[email] - ✅
test_register_missing_required_field[password] - ✅
test_register_missing_required_field[birth_date] - ✅
test_register_requires_at_least_one_contact - ✅
test_register_birth_date_must_be_valid_date
Почему они проходят? Они ожидают ошибку валидации и получают её (хоть и по другим причинам).
🔍 Анализ причин
Вопрос 1: Почему avatar и gender обязательные?
Вероятно, это бизнес-требование:
- Avatar: Для корпоративной системы важно иметь фото сотрудника
- Gender: Для HR-целей и документооборота
Вопрос 2: Должны ли они быть обязательными при регистрации?
Два подхода:
Вариант A: Сделать опциональными для регистрации
avatar = Base64ImageField(required=False, allow_null=True)
gender = serializers.ChoiceField(
required=False,
allow_null=True,
choices=((1, "Мужской"), (2, "Женской")),
)
Плюсы: Упрощает регистрацию Минусы: Может нарушить бизнес-логику
Вариант B: Исправить тесты (добавить поля)
def register_payload(**overrides):
data = {
"first_name": "Иван",
"last_name": "Иванов",
"phone_number": "+79990000001",
"email": "ivan@example.com",
"password": "Str0ngPass!",
"birth_date": "1990-01-01",
"telegram": "@ivan",
"avatar": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", # 1x1 прозрачный PNG
"gender": 1, # Мужской
}
return data
Плюсы: Соответствует текущей бизнес-логике Минусы: Нужно обновить все тесты
🎯 Рекомендации
✅ РЕКОМЕНДУЕМОЕ РЕШЕНИЕ: Исправить сериализатор
Причина: Модель Employee позволяет avatar и gender быть необязательными. Сериализатор должен соответствовать модели.
Изменение в backend/api/v1/employees/serializers.py:
class RegisterSerializer(serializers.Serializer):
# ... другие поля ...
# Было:
# avatar = Base64ImageField(required=True)
# gender = serializers.ChoiceField(required=True, ...)
# Стало:
avatar = Base64ImageField(required=False, allow_null=True) # ✅ Соответствует модели
gender = serializers.ChoiceField(
required=False, # ✅ Соответствует модели
choices=((1, "Мужской"), (2, "Женский"), (0, "Не указано")),
default=0, # ✅ Соответствует модели
error_messages={
'invalid_choice': 'Выберите корректное значение пола.',
}
)
Преимущества:
- ✅ Соответствие архитектуре (модель → сериализатор → API)
- ✅ Упрощение регистрации для пользователей
- ✅ Тесты пройдут без изменений
- ✅ Возможность заполнить профиль позже
Альтернатива: Обновить тесты (НЕ рекомендуется)
Обновить register_payload() в тестах:
def register_payload(**overrides):
# Минимальное base64 изображение (1x1 пиксель)
MINIMAL_AVATAR = (
"data:image/png;base64,"
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
)
data = {
"first_name": "Иван",
"last_name": "Иванов",
"phone_number": "+79990000001",
"email": "ivan@example.com",
"password": "Str0ngPass!",
"birth_date": "1990-01-01",
"telegram": "@ivan",
"avatar": MINIMAL_AVATAR, # ✅ Добавлено
"gender": 1, # ✅ Добавлено (1 = Мужской)
}
data.update(overrides)
return data
Недостатки этого подхода:
- ❌ Не решает архитектурную проблему (несоответствие модели и сериализатора)
- ❌ Усложняет регистрацию в production (требует обязательную загрузку аватара)
- ❌ Требует изменений в тестах вместо исправления кода
Долгосрочное решение (архитектурное)
Вариант 1: Разделить регистрацию на этапы
- Этап 1: Email, пароль, базовая информация
- Этап 2: После верификации email → заполнение профиля (avatar, gender)
Вариант 2: Сделать поля условно обязательными
- При регистрации: опциональные
- При активации аккаунта: требуется заполнить
- При первом входе: напоминание заполнить
📊 Влияние на production
⚠️ Текущая ситуация
Если avatar и gender обязательны:
- Фронтенд должен отправлять эти поля при регистрации
- Если фронтенд не отправляет → регистрация не работает
- Пользователи не могут зарегистрироваться
✅ Вопросы для проверки
-
Работает ли регистрация на production?
- Если да → значит фронтенд корректно отправляет поля
- Если нет → критическая ошибка
-
Как фронтенд отправляет avatar?
- Base64 строка
- File upload
- URL изображения
-
Обязателен ли gender в бизнес-логике?
- Требование HR
- Требование законодательства
- Опционально
🚀 Заключение
Основная проблема: Рассинхронизация между тестами и сериализатором
- Сериализатор требует
avatarиgender - Тесты не передают эти поля
Решение: Нужно привести в соответствие:
- ЛИБО сделать поля опциональными в сериализаторе
- ЛИБО добавить поля в тестовые данные
Рекомендация: Обновить тесты (добавить avatar и gender), так как это, вероятно, соответствует реальному поведению фронтенда.