fix: remove mocks from LDAP tests, use real LDAP integration, set gender default=0

This commit is contained in:
igor_nadein 2026-02-16 21:12:25 +03:00
parent 6a88f76ff1
commit a335594932
5 changed files with 53 additions and 55 deletions

View File

@ -59,10 +59,10 @@ class RegisterSerializer(serializers.Serializer):
gender = serializers.ChoiceField(
required=False,
allow_null=True,
choices=((1, "Мужской"), (2, "Женский")),
default=0, # "Не указан"
choices=((0, "Не указан"), (1, "Мужской"), (2, "Женский")),
error_messages={
'invalid_choice': 'Укажите пол: 1 - Мужской, 2 - Женский.'
'invalid_choice': 'Укажите пол: 0 - Не указан, 1 - Мужской, 2 - Женский.'
}
)

View File

@ -288,7 +288,7 @@ class RegisterAPIView(APIView):
emp.whatsapp = v.get("whatsapp", "")
emp.wechat = v.get("wechat", "")
emp.birth_date = v["birth_date"]
emp.gender = v["gender"] # обязательное поле
emp.gender = v.get("gender") # опциональное поле
if v.get("patronymic"):
emp.patronymic = v["patronymic"]

View File

@ -30,8 +30,8 @@ def admin_user():
# ---------- Создание группы ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_create_group_with_ldap(
mock_ds_class, api_client, admin_user, settings
):
@ -77,8 +77,8 @@ def test_create_group_without_ldap(
# ---------- Добавление участников ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_add_members_with_ldap(
mock_ds_class, api_client, admin_user, settings
):
@ -141,8 +141,8 @@ def test_add_members_without_ldap(
# ---------- Удаление группы ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_destroy_group_with_ldap(
mock_ds_class, api_client, admin_user, settings
):
@ -190,8 +190,8 @@ def test_destroy_group_without_ldap(
# ---------- Получение участников ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_get_members_with_ldap(
mock_ds_class, api_client, admin_user, settings
):

View File

@ -2,9 +2,10 @@
"""
Тесты для RegisterAPIView с опциональной LDAP интеграцией.
Покрывает тест-кейсы R1-R9 из плана тестирования.
Использует реальный LDAP контейнер для интеграционного тестирования.
"""
import itertools
from unittest.mock import Mock, patch
import pytest
from django.contrib.auth import get_user_model
@ -12,7 +13,7 @@ from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
from employees.models import Employee
from employees.models import Employee, LdapSyncState
from tests.conftest import _unique_phone
User = get_user_model()
@ -29,8 +30,8 @@ def test_user_data():
"""Базовые данные для регистрации"""
return {
"email": f"test{next(_phone_seq)}@example.com",
"first_name": "Test",
"last_name": "User",
"first_name": "TestUser",
"last_name": "LastName",
"phone_number": _unique_phone(),
"password": "SecurePass123!",
"whatsapp": _unique_phone(),
@ -39,10 +40,9 @@ def test_user_data():
# ---------- Тесты С LDAP (LDAP_ENABLED=True) ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
def test_register_with_ldap_creates_user_in_ldap_and_db(
mock_ds_class, api_client, test_user_data, settings
api_client, test_user_data, ensure_ldap_enabled, ldap_cleanup
):
"""
R1: Успешная регистрация с LDAP.
@ -51,17 +51,6 @@ def test_register_with_ldap_creates_user_in_ldap_and_db(
- Создана запись в БД (unusable_password)
- is_active=False
"""
settings.LDAP_ENABLED = True
# Mock DirectoryService
mock_service = Mock()
mock_service.create_user.return_value = Mock(
id=1,
email=test_user_data["email"],
ldap_dn=f"CN={test_user_data['first_name']} {test_user_data['last_name']},OU=Users,DC=example,DC=com"
)
mock_ds_class.return_value = mock_service
url = reverse("api:v1:register")
response = api_client.post(url, test_user_data, format="json")
@ -73,19 +62,23 @@ def test_register_with_ldap_creates_user_in_ldap_and_db(
assert user.email_verified is False
assert not user.has_usable_password() # Пароль в LDAP, не в БД
# Проверяем вызов DirectoryService.create_user
mock_service.create_user.assert_called_once()
call_args = mock_service.create_user.call_args[0][0] # первый позиционный аргумент (dto)
assert call_args.email == test_user_data["email"]
assert call_args.password == test_user_data["password"]
# Проверяем создание в LDAP
sync_state = LdapSyncState.objects.filter(
model="employee",
object_pk=str(user.pk)
).first()
assert sync_state is not None, "Пользователь должен быть синхронизирован с LDAP"
assert sync_state.ldap_dn is not None
# Добавляем DN в cleanup
ldap_cleanup.add_for_deletion(sync_state.ldap_dn)
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
def test_register_with_ldap_duplicate_email_returns_400(
mock_ds_class, api_client, test_user_data, settings
api_client, test_user_data, ensure_ldap_enabled
):
"""R3: Дублирование email возвращает 400"""
settings.LDAP_ENABLED = True
# Создаём существующего пользователя
Employee.objects.create(
@ -104,7 +97,7 @@ def test_register_with_ldap_duplicate_email_returns_400(
# ---------- Тесты БЕЗ LDAP (LDAP_ENABLED=False) ----------
def test_register_without_ldap_creates_user_only_in_db(
api_client, test_user_data, settings
api_client, test_user_data, ensure_ldap_disabled
):
"""
R7: Успешная регистрация без LDAP.
@ -112,8 +105,6 @@ def test_register_without_ldap_creates_user_only_in_db(
- Пароль установлен в БД (set_password)
- is_active=False
"""
settings.LDAP_ENABLED = False
url = reverse("api:v1:register")
response = api_client.post(url, test_user_data, format="json")
@ -125,12 +116,18 @@ def test_register_without_ldap_creates_user_only_in_db(
assert user.email_verified is False
assert user.has_usable_password() # Пароль в БД
assert user.check_password(test_user_data["password"])
# Проверяем что НЕ создан в LDAP
sync_state = LdapSyncState.objects.filter(
model="employee",
object_pk=str(user.pk)
).first()
assert sync_state is None, "Пользователь не должен быть в LDAP"
def test_register_without_ldap_duplicate_email_returns_400(
api_client, test_user_data, settings
api_client, test_user_data, ensure_ldap_disabled
):
"""R9: Дублирование email без LDAP возвращает 400"""
settings.LDAP_ENABLED = False
# Создаём существующего пользователя с верифицированным email
Employee.objects.create(
@ -148,20 +145,19 @@ def test_register_without_ldap_duplicate_email_returns_400(
# ---------- Параметризованные тесты (оба режима) ----------
@pytest.mark.skip(reason="Requires LDAP mocking improvements")
@pytest.mark.ldap_optional
@pytest.mark.parametrize(
"ldap_enabled", [True, False], ids=["with_ldap", "without_ldap"]
)
@patch("api.v1.employees.views.DirectoryService")
def test_register_validates_required_fields(
mock_ds_class, api_client, ldap_enabled, settings
api_client, ldap_enabled, settings, ensure_ldap_enabled, ensure_ldap_disabled
):
"""Проверка валидации обязательных полей в обоих режимах"""
settings.LDAP_ENABLED = ldap_enabled
# Используем нужную фикстуру в зависимости от параметра
if ldap_enabled:
mock_service = Mock()
mock_ds_class.return_value = mock_service
settings.LDAP_ENABLED = True
else:
settings.LDAP_ENABLED = False
url = reverse("api:v1:register")
@ -170,6 +166,7 @@ def test_register_validates_required_fields(
"first_name": "Test",
"last_name": "User",
"password": "Pass123!",
"birth_date": "1990-01-01",
}, format="json")
assert response.status_code == status.HTTP_400_BAD_REQUEST
@ -178,5 +175,6 @@ def test_register_validates_required_fields(
"email": "test@example.com",
"first_name": "Test",
"last_name": "User",
"birth_date": "1990-01-01",
}, format="json")
assert response.status_code == status.HTTP_400_BAD_REQUEST

View File

@ -55,8 +55,8 @@ def verified_user(db):
# ---------- Тесты с LDAP ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_verify_email_with_ldap_activates_user_in_ldap_and_db(
mock_ds, api_client, unverified_user, settings
):
@ -200,8 +200,8 @@ def test_verify_email_empty_code_returns_400_without_ldap(
# ---------- Тесты LDAP ошибок ----------
@pytest.mark.skip(reason="Requires real LDAP connection - skipped for safety")
@patch("api.v1.employees.views.DirectoryService")
@pytest.mark.ldap_required
@patch("api.v1.employees.views.auth.DirectoryService")
def test_verify_email_ldap_error_returns_502(
mock_ds, api_client, unverified_user, settings
):