Unit vs Integration тесты
1) Зачем различать типы тестов
Правильная грануляция тестов делает разработку предсказуемой: Unit ловят дефекты логики быстро и дешево; Integration проверяют связки модулей, реальный транспорт и «клей». Вместе они уменьшают регресс и ускоряют релизы.
2) Определения и границы
Unit-тест
Проверяет малую единицу поведения (функцию, класс, use-case) в изоляции.
Внешние зависимости заменены (mock/stub/fake).
Быстрый (мс–десятки мс), детерминированный.
Integration-тест
Проверяет взаимодействие нескольких реальных компонентов: БД, брокер (Kafka/RabbitMQ), HTTP/gRPC, файловая система, кэш.
Минимум моков, реальные протоколы.
Медленнее (сотни мс–секунды), дороже по поддержке.
3) Пирамида тестирования (а не ледяной рожок)
Основание: Unit (70–80% по количеству) — дешево, быстро.
Средний слой: Integration/Component (15–25%) — критичные пути и контракты.
Верх: E2E/UX/Exploratory (5–10%) — минимально достаточно.
По бокам: Static Analysis/Lint/Type check и Mutation testing как усилители качества.
4) Что отдавать Unit, а что — Integration
5) Данные и фикстуры
Unit
Inline фикстуры/билдеры (factory methods).
Табличные тесты (table-driven) для граничных значений.
Property-based подход для инвариантов (например, «сумма дебетов = сумме кредитов»).
Integration
Hermetic окружение: Testcontainers/Docker Compose поднимают `postgres + redis + kafka + wiremock`.
Начальный seed в БД/кэше и очистка после (транзакция/rollback, truncate).
Часы/таймеры — фейковые (контролируемые), иначе флаки.
6) Инструменты и паттерны
Mocks/Stubs/Fakes/Spies:- Stub — фиксированный ответ (дешево).
- Mock — проверка взаимодействий/количества вызовов.
- Fake — упрощенная реализация (например, In-Memory Repo).
- Contract testing (CDC): Pact/Swagger-based — фиксируем ожидания клиента и проверяем провайдера.
- WireMock/MockServer — HTTP-заглушки для сторонних сервисов.
- Testcontainers — живые БД/брокеры локально и в CI без «зоопарка».
7) Примеры
7.1 Unit: идемпотентность платежа (pseudocode)
python def test_idempotent_create_payment_returns_same_id():
repo = InMemoryPayments()
service = Payments(repo)
first = service. create(amount=100, key="abc")
second = service. create(amount=100, key="abc")
assert first. id == second. id assert repo. count() == 1
7.2 Integration: подпись вебхука (HMAC) + повтор
bash docker-compose: app + redis + wiremock (PSP)
docker compose -f docker-compose. test. yml up -d pytest -m "integration and webhook" -q
Тест:
- WireMock отдает событие с `X-Timestamp` и подписью.
- Приложение проверяет HMAC, дедуплицирует по `event_id`, повтор через 5 сек не создает дубль.
- Проверяем `200` и, что запись одна.
7.3 CDC: контракт клиента к провайдеру
Клиент формирует Pact (ожидание: `POST /v1/payout` → `201` со схемой).
Провайдер в CI прогоняет верификацию контракта на своем стенде.
8) Скорость, параллельность, флейки
Unit должны работать <100 мс на тест; пакет — секунды.
Integration — параллелить по контейнерам/портам; использовать миграции на запуске.
- контролируемое время (fake clock),
- ожидания «по явному событию», а не `sleep`,
- стабильные пороги (ретраи с джиттером тестировать детерминированно).
9) Метрики качества
Coverage (строчки/ветви): полезно для наблюдения тренда, но не цель.
Mutation testing (PIT/Mutmut): показывает, «убивают ли» тесты ложные изменения — реальная сила ассуренса.
Test duration и flaky rate: алерты при росте.
Defect containment: доля багов, перехваченных до продакшена.
10) Встраивание в CI/CD
Джобы: unit → integration → e2e (fan-out по сервисам).
Кэш зависимостей, параллельные матрицы по БД/языкам/версиям.
Отчеты: JUnit/Allure + артефакты логов контейнеров (при падениях).
Gate: «зеленые unit + критические integration» — условие мержа; e2e — на nightly.
yaml strategy:
matrix:
db: [postgres14, postgres16]
steps:
- run: docker run -d --name db -e POSTGRES_PASSWORD=pw postgres:${{ matrix. db }}
- run: pytest -m "unit" -q
- run: pytest -m "integration" -q
11) Микросервисы и события
Сервисные контракты: OpenAPI/Protobuf версионируются; тесты на совместимость (backward).
Event-driven:- Unit: маппинг доменных событий и инварианты.
- Integration: публикация/подписка в реальном брокере (Kafka), outbox/inbox семантика, exactly-once имитация (по крайней мере — idempotent).
- Тесты ретраев/дубликатов/переупорядочивания (out-of-order).
12) Данные и изоляция в Integration
Каждый тест → уникальная схема/БД (Testcontainers JDBC URL `?TC_TMPFS=/var/lib/postgresql/data:rw`).
Транзакционные фикстуры (begin→run→rollback) ускоряют чистку.
Для Redis/кэша — ключевой префикс `test:${RUN_ID}:` и `FLUSHDB` в teardown.
13) Специфика iGaming/финансов
Деньги и лимиты: property-based тесты на инварианты (баланс ≥ 0, суммарные ограничения).
Регуляторика: проверка журналирования (аудит-лог пишется), неизменяемые события.
Платежи/PSP: интеграционные тесты HMAC/mTLS, `Retry-After`, идемпотентность, дедуп `jti`.
Ответственная игра: тесты правил порогов/кулдаунов; «вчера→сегодня» на fake clock.
14) Антипаттерны
«Unit», которые поднимают БД/HTTP — это уже integration (путают слои и замедляют CI).
Высокий coverage за счет пустых утверждений («покрыли, но не проверили»).
Моки логики сторонних сервисов там, где нужен контракт (ломается при обновлении).
Тесты с `sleep(5)` вместо ожиданий события/условия.
Общая тестовая БД для параллельных тестов → гонки и флейки.
15) Чек-лист prod-готовности
- Пирамида определена: % долей Unit/Integration/E2E и цели по времени прогона.
- Unit изолированы, быстрые, покрывают граничные значения и инварианты.
- Integration используют hermetic-окружение (Testcontainers/Compose), без общих стейтов.
- Контрактные тесты (OpenAPI/Pact) верифицируются в CI.
- Данные тестов — управляемые: seed/rollback/префиксы, fake clock.
- Параллельный прогон, отчеты JUnit/Allure, артефакты логов контейнеров.
- Метрики: duration, flaky rate, mutation score; алерты на деградацию.
- Платежные/вебхук-сценарии: HMAC/mTLS, ретраи, идемпотентность, дедуп.
- Документация стратегии и примеры шаблонов тестов.
16) TL;DR
Unit — максимум логики, минимум окружения; Integration — минимум моков, максимум реализма. Держите пирамиду: быстрые Unit ловят 80% дефектов, Integration подтверждают связки и контракты. Используйте hermetic-контейнеры, контрактные тесты, fake clock и параллельность. Мерьте не только coverage, но и mutation score и flaky rate. Особо проверьте платежные/вебхук-пути: подписи, ретраи и идемпотентность.