# Backend testing Перед нетривиальными тестами сформулируй [общий Test Intent](engineering.md#test-intent); отдельный документ не требуется. Trivial low-risk изменения обходятся без него. ## Выбор уровня Проверяй риски доступа, денежных расчётов, целостности данных, конкурентных изменений, публичного контракта и подтверждённых регрессий. Тесты должны различать правильное и неправильное наблюдаемое поведение. | Что меняется | Проверка | | --- | --- | | Pure mapper/decimal/domain branch | Unit со значимыми edge cases | | Service orchestration/access/retry policy | Jest с mocks внешних boundaries и observable outcome | | Pipe/guard/cookie/status/HTTP error | Configured Nest HTTP boundary; прямого вызова метода controller недостаточно | | OpenAPI metadata/wire schema | `test:openapi-contract` + configured HTTP tests | | DB constraint/CAS/transaction/migration | Integration с изолированной реальной DB | | Только DTO declarations/thin wiring | Existing contract/type/build без искусственного unit test | Unit specs colocated в `src/**/*.spec.ts`; HTTP/integration — `test/`. Мокируй T-Bank, время и нужную DB boundary, а не проверяемую business-функцию. Не зови реальный внешний account/API. Expected error/code, отсутствие запроса при недопустимом доступе и сохранение данных важнее private method call count. ## Случаи и примеры - [BrokerageAccountsService tests](../../src/modules/investments/brokerage-accounts/brokerage-accounts.service.spec.ts): отсутствие connection не вызывает upstream, нормализация и точные суммы. - [AuthService tests](../../src/modules/auth/application/auth.service.spec.ts): invalid/expired/superseded token и concurrent rotation; mock race test не является доказательством DB transaction. - [HTTP filter tests](../../src/common/filters/http-exception.filter.spec.ts): безопасный error envelope. - [OpenAPI integration](../../test/openapi-contract.e2e-spec.ts): генератор без сервера + configured app; временный JSON, без versioned snapshot и без T-Bank. При bug сначала воспроизведи именно его исход, затем исправь responsible owner. Не создавай tests для каждой декларации, logs строки или поведения Prisma/Nest без собственного инварианта. Coverage не имеет общего threshold. ## Команды и ограничения Итерация: `npm test -- --runInBand `, затем нужный typecheck/lint. Полный `npm run verify` включает lint, оба typecheck, Jest и build. `npm run test:openapi-contract` — отдельный required check при wire contract change. `npm run test:e2e` запускает функциональные HTTP suites через изолированный SQLite runner; `npm run test:sqlite` — только auth/cards. Каждая suite получает новую временную базу со штатными migrations. Прямой Jest без runner отклоняется до DB-запросов. Большой latency/load benchmark запускается отдельно через `npm run test:performance`: его абсолютный wall-clock budget не является merge gate на shared runner. `prisma.config.ts` исключает влияние унаследованного `RUST_LOG=warn/error` на fresh migration; точная Prisma version принадлежит manifest/lockfile. Подробности и регрессия запуска — [Backend README](../../README.md#реальная-sqlite-и-сохранность-данных). HTTP suites требуют разрешения открывать локальные порты. Ошибка sandbox не считается успешным тестом; повторите проверку в подходящем окружении. Для schema/data changes дополнительно `npm run test:durability -- `. Матрица рисков и подготовка совместимой предыдущей сборки — в том же README. Mock Prisma не заменяет доказательство реальной DB concurrency.