9.5 KiB
Backend unit-тесты
Назначение
Unit- и service-тесты backend проверяют бизнес-логику без запуска HTTP API:
- доменные правила записи на лекции;
- преобразование сущностей в DTO;
- фильтрацию, пагинацию и связи курсов;
- дерево тегов;
- управление ролями и профилями пользователей.
Security-тесты авторизации находятся в том же тестовом проекте, но это отдельный интеграционный набор: они запускают API через WebApplicationFactory и проверяют HTTP-доступ к endpoint-ам.
Где лежат файлы
- EnrollmentSlotPolicyTests.cs - правила лимита активных записей по уровню.
- MappingExtensionsTests.cs - маппинг доменных сущностей в DTO.
- CourseServiceTests.cs - фильтры, пагинация и теги курсов.
- TagServiceTests.cs - фильтры тегов и построение дерева.
- UserServiceTests.cs - статистика, роли, профили и список пользователей.
- EndpointAuthorizationTests.cs - security-тесты ролевого доступа к API.
- ApiWebApplicationFactory.cs - тестовый запуск API.
- TestJwtFactory.cs - генерация JWT для ролей в security-тестах.
Тестовый проект: 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. Это интеграционные тесты, которые отправляют реальные 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:
- Если endpoint требует авторизации, добавьте его в
AuthenticatedEndpoints. - Укажите правильную роль или отдельные кейсы для нескольких ролей.
- Для role-specific endpoint-а заполните
forbiddenролями, которые должны получать403. - Если endpoint публичный, добавьте его в
AnonymousEndpoints. - Для
POST,PUT,PATCHendpoint-ов добавьте минимальное валидное тело запроса, чтобы тест дошел до авторизации и не падал на model binding раньше времени.
Security-тест считается успешным для правильной роли, если ответ не 401 и не 403. Это намеренно: после авторизации endpoint может вернуть 404, 400, 409 или другой доменный ответ из-за тестовых данных, и это не является ошибкой проверки доступа.
Как запускать
Из корня репозитория:
dotnet test backend/UniVerse.sln --no-restore
Как добавлять новые unit/service-тесты
- Размещайте тесты рядом с проверяемой областью внутри
backend/UniVerse.Api.Tests. - Для сервисов с EF используйте InMemory
AppDbContextс уникальным именем базы. - Мокайте только внешние зависимости и соседние сервисы через
NSubstitute. - Не запускайте
WebApplicationFactory, если проверяется не HTTP/auth behavior. - Покрывайте не только успешный сценарий, но и доменные ошибки:
NotFoundException,ConflictException,ForbiddenException.
Текущий baseline
После добавления unit/service-тестов и с учетом существующих security-тестов полный backend test suite проходит:
Passed: 303, Failed: 0, Skipped: 0