Files
UniVerse/docs/backend-unit-tests.md
T
serega404 ef2fd39508
Backend CI / build-and-test (push) Successful in 48s
🚀 Create and publish a Docker image / Detect changes in backend and frontend (push) Successful in 5s
🚀 Create and publish a Docker image / Build & publish backend image (push) Successful in 24s
🚀 Create and publish a Docker image / Build & publish frontend image (push) Failing after 14s
🚀 Create and publish a Docker image / Update stack on Portainer (push) Successful in 2s
feat: добавил новые юнит-тесты для сервисов и маппинга
2026-05-28 19:51:34 +03:00

144 lines
9.5 KiB
Markdown
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.
# Backend unit-тесты
## Назначение
Unit- и service-тесты backend проверяют бизнес-логику без запуска HTTP API:
- доменные правила записи на лекции;
- преобразование сущностей в DTO;
- фильтрацию, пагинацию и связи курсов;
- дерево тегов;
- управление ролями и профилями пользователей.
Security-тесты авторизации находятся в том же тестовом проекте, но это отдельный интеграционный набор: они запускают API через `WebApplicationFactory` и проверяют HTTP-доступ к endpoint-ам.
## Где лежат файлы
- [EnrollmentSlotPolicyTests.cs](../backend/UniVerse.Api.Tests/Domain/EnrollmentSlotPolicyTests.cs) - правила лимита активных записей по уровню.
- [MappingExtensionsTests.cs](../backend/UniVerse.Api.Tests/Application/MappingExtensionsTests.cs) - маппинг доменных сущностей в DTO.
- [CourseServiceTests.cs](../backend/UniVerse.Api.Tests/Courses/CourseServiceTests.cs) - фильтры, пагинация и теги курсов.
- [TagServiceTests.cs](../backend/UniVerse.Api.Tests/Tags/TagServiceTests.cs) - фильтры тегов и построение дерева.
- [UserServiceTests.cs](../backend/UniVerse.Api.Tests/Users/UserServiceTests.cs) - статистика, роли, профили и список пользователей.
- [EndpointAuthorizationTests.cs](../backend/UniVerse.Api.Tests/Authorization/EndpointAuthorizationTests.cs) - security-тесты ролевого доступа к API.
- [ApiWebApplicationFactory.cs](../backend/UniVerse.Api.Tests/Helpers/ApiWebApplicationFactory.cs) - тестовый запуск API.
- [TestJwtFactory.cs](../backend/UniVerse.Api.Tests/Helpers/TestJwtFactory.cs) - генерация JWT для ролей в security-тестах.
Тестовый проект: [UniVerse.Api.Tests.csproj](../backend/UniVerse.Api.Tests/UniVerse.Api.Tests.csproj).
## Тестовый стек
- `xUnit` - test runner и assertions.
- `NSubstitute` - mock-объекты для сервисных зависимостей.
- `Microsoft.EntityFrameworkCore.InMemory` - изолированная InMemory БД для service-тестов.
Каждый service-тест создает отдельный `AppDbContext` с уникальным именем базы через `Guid.NewGuid()`, чтобы данные разных тестов не пересекались.
## Что покрыто
### EnrollmentSlotPolicy
Проверяется, что `GetLimitForLevel` выбирает последний подходящий threshold:
- уровни ниже первого правила получают базовый лимит;
- уровни между threshold используют предыдущий лимит;
- уровни выше последнего threshold используют максимальный лимит;
- публичный список `Rules` остается в ожидаемом порядке.
### MappingExtensions
Проверяется стабильность DTO-маппинга:
- роли пользователя сортируются одинаково в `UserDto`, `CurrentUserDto` и `UserAuthDto`;
- лекции корректно считают записи и используют fallback для отсутствующих navigation properties;
- отзывы переносят поля LLM-анализа;
- дерево тегов маппится рекурсивно.
### CourseService
Проверяется поведение без HTTP-слоя:
- совместная работа фильтров `Search`, `IsSynced`, `TagId`;
- корректные `TotalCount`, `Page`, `PageSize`, `TotalPages`;
- добавление связи курс-тег;
- ошибки при повторной связи или отсутствующем курсе/теге.
### TagService
Проверяется:
- фильтрация по `TagType` и `ParentId`;
- сортировка по имени;
- запрет создания дочернего тега без существующего родителя;
- построение вложенного дерева тегов.
### UserService
Проверяется:
- статистика пользователя, прогресс уровня и лимиты записей;
- `SetRolesAsync` удаляет дубли ролей;
- пустой набор ролей отклоняется;
- профили студента и преподавателя создаются и не дублируются;
- `GetAllAsync` фильтрует по поиску, активности и одиночной роли;
- пагинация пользователей идет в порядке `CreatedAt` по убыванию.
## Security-тесты авторизации
Security-тесты находятся в [EndpointAuthorizationTests.cs](../backend/UniVerse.Api.Tests/Authorization/EndpointAuthorizationTests.cs). Это интеграционные тесты, которые отправляют реальные HTTP-запросы в тестовый API через `ApiWebApplicationFactory`.
Они проверяют не бизнес-результат endpoint-а, а сам факт прохождения или блокировки авторизации:
- анонимный запрос к защищенному endpoint-у получает `401 Unauthorized`;
- запрос с неподходящей ролью получает `403 Forbidden`;
- запрос с подходящей ролью не получает `401` или `403`;
- публичные endpoint-ы из `AnonymousEndpoints` доступны без JWT и не возвращают `401` от middleware авторизации.
Таблица защищенных endpoint-ов задается в методе `AuthenticatedEndpoints`. Каждый кейс описывает:
- человекочитаемое имя сценария;
- HTTP-метод;
- URL;
- роль, которая должна пройти авторизацию;
- роли, которые должны получить `403`;
- опциональное JSON-тело запроса.
Для endpoint-ов, доступных любой авторизованной роли, используется обычная тестовая роль, чаще `Student`, и пустой список запрещенных ролей. Для endpoint-ов с несколькими разрешенными ролями добавляется отдельный кейс на каждую разрешенную роль, например `Admin` и `Teacher`.
JWT для ролей создаются через `TestJwtFactory.BearerHeader(role)`. Это позволяет проверять backend-авторизацию без Microsoft OAuth flow и без реального входа пользователя.
## Как обновлять security-тесты
При добавлении или изменении API endpoint-а нужно обновить `EndpointAuthorizationTests`:
1. Если endpoint требует авторизации, добавьте его в `AuthenticatedEndpoints`.
2. Укажите правильную роль или отдельные кейсы для нескольких ролей.
3. Для role-specific endpoint-а заполните `forbidden` ролями, которые должны получать `403`.
4. Если endpoint публичный, добавьте его в `AnonymousEndpoints`.
5. Для `POST`, `PUT`, `PATCH` endpoint-ов добавьте минимальное валидное тело запроса, чтобы тест дошел до авторизации и не падал на model binding раньше времени.
Security-тест считается успешным для правильной роли, если ответ не `401` и не `403`. Это намеренно: после авторизации endpoint может вернуть `404`, `400`, `409` или другой доменный ответ из-за тестовых данных, и это не является ошибкой проверки доступа.
## Как запускать
Из корня репозитория:
```bash
dotnet test backend/UniVerse.sln --no-restore
```
## Как добавлять новые unit/service-тесты
1. Размещайте тесты рядом с проверяемой областью внутри `backend/UniVerse.Api.Tests`.
2. Для сервисов с EF используйте InMemory `AppDbContext` с уникальным именем базы.
3. Мокайте только внешние зависимости и соседние сервисы через `NSubstitute`.
4. Не запускайте `WebApplicationFactory`, если проверяется не HTTP/auth behavior.
5. Покрывайте не только успешный сценарий, но и доменные ошибки: `NotFoundException`, `ConflictException`, `ForbiddenException`.
## Текущий baseline
После добавления unit/service-тестов и с учетом существующих security-тестов полный backend test suite проходит:
```text
Passed: 303, Failed: 0, Skipped: 0
```