Files
slm-design/DRAFT/level-3/domains/testing.md

71 lines
5.4 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.

# Тестирование домена
> Проверка границ и поведения Level 3.
## Связанные правила
- [`SLM-L3-TEST-R014`](../../rules/level-3.md#slm-l3-test-r014)
- [`SLM-L3-FACTORY-R006`](../../rules/level-3.md#slm-l3-factory-r006)
- [`SLM-L3-ASSEMBLY-R010`](../../rules/level-3.md#slm-l3-assembly-r010)
## Принцип размещения
Тест находится рядом с модулем-владельцем проверяемой ответственности. У домена нет общей корневой папки `tests/`.
| Проверяемая граница | Владелец теста |
|---|---|
| Предметные сценарии, состояние и ошибки домена | `business` |
| Чистая функция бизнес-логики | Соответствующий сегмент `business` |
| Реализация порта | Адаптер |
| Выбор зависимостей, область жизни и очистка | Модуль в `presets` |
| Провайдер, хук и жизненный цикл React | `react` |
| Граф нескольких доменов | Модуль-владелец графа |
| Полный пользовательский поток | Точка входа сквозного теста приложения |
## Тесты через фабрику
Тесты через фабрику являются главным доказательством публичного поведения бизнес-логики. Они импортируют только публичный API `business` и передают управляемые тестовые реализации портов:
```ts
import {
AUTH_ERROR_CODES,
authFactory,
isAuthError,
} from '@/domains/auth/business'
it('maps source failure to domain error', async () => {
const requestCode = vi.fn().mockRejectedValue(new Error('Network failed'))
const api = authFactory(createAuthTestDeps({ requestCode }))
await expect(api.requestPhoneOtp('+79991112233')).rejects.toMatchObject({
code: AUTH_ERROR_CODES.PHONE_OTP_REQUEST_FAILED,
})
})
```
Такой набор тестов проверяет форму публичного API, отсутствие побочных эффектов при создании, успешные и ошибочные сценарии, проверку входных данных, переходы состояния и порядок внешних операций.
Тест `business` не использует React, реальный SDK, хранилище или типовую сборку приложения. Если сценарий нельзя проверить без них, техническая зависимость проникла внутрь бизнес-логики.
## Вспомогательная тестовая сборка
Закрытая тестовая функция уменьшает повторение, но не является модулем в `presets`:
```ts
const { api, ports, state } = createAuthTestHarness({ requestCode })
```
Она создаёт новый экземпляр для каждого теста, допускает нужные сценарию замены и не экспортируется через рабочую точку входа. Модуль `presets/testing` по умолчанию не создаётся.
## Тесты остальных ролей
Тест адаптера проверяет вызванную техническую операцию, переданные данные, преобразование аргументов, результат или ошибку согласно контракту порта и очистку подписки. Он не повторяет преобразование ошибок домена и полный набор предметных сценариев.
Тест типовой сборки проверяет полный набор портов, выбор адаптеров, отсутствие ввода-вывода при создании, область жизни экземпляра, передачу операции очистки и границу клиента и сервера. Он не повторяет успешные предметные сценарии.
Тест React получает тестовый `AuthApi` и проверяет провайдер, хук доступа, обновление по `subscribe`, очистку после размонтирования и поведение в `StrictMode`. Минимальный интеграционный тест с настоящей фабрикой добавляется только при отдельном риске интеграции.
## Минимальный набор
Тест создаётся в ответ на реальный риск, а не ради заполнения каркаса. При этом публичный предметный сценарий требует теста через фабрику, типовая сборка приложения — теста сборки, адаптер с нетривиальным преобразованием данных — теста адаптера, а модуль React с поведением жизненного цикла — теста фреймворка.