← Python мануфактура

Після цього уроку ви зможете

Конспект і таймкоди

0:00

Перевірка створеної сутності в event-driven системі

Питання учасника: якщо POST повернув 200 OK із порожнім body, чи достатньо цього для перевірки створення сутності. В event-driven архітектурі успішна відповідь може означати лише прийняття команди, а фактичний запис з’явиться пізніше, тому наступний GET перевіряє спостережуваний результат.

Лектор розділяє два типи coverage: сценарій для конкретного ресурсу та повний business flow. CRUD/resource test локалізує помилку в операціях над сутністю; сценарний тест перевіряє, що ланцюжок бізнес-дій працює цілісно. Один тип не замінює інший, бо дефект може проявитися лише на конкретному стику.

Що змінилося після запису

Що змінилося після запису

У відеоУ відео 200 OK використано як приклад response, після якого сутність у distributed system ще може потребувати окремої перевірки через GET.

АктуальноЗа RFC 9110 стандартним сигналом незавершеної асинхронної обробки є 202 Accepted; 200 OK означає, що request succeeded. Реальний тест має спиратися на контракт конкретного API й не виводити completion semantics лише зі status class.

Що змінилосяRFC 9110 published 2022-06

Термін

HTTP success semantics

RFC 9110 визначає 200 OK як успішне виконання request. Для POST content описує status або результат дії. 202 Accepted означає, що request прийнято, але обробку ще не завершено.

Практика

Матриця перевірок створення ресурсу

  1. Для одного POST endpoint опишіть immediate response assertion і спосіб перевірки eventual result.
  2. Додайте resource-schema assertions і один business-flow assertion.
  3. Позначте, який тест локалізує кожен failure.

Результат: Таблиця з чотирма checks, test level і failure signal.

2:40

Шари від таблиці до API response

На спрощеній схемі є database table із полями користувача, entity для роботи з нею, service із бізнес-логікою та mapping, controller з endpoints і DTO, яке повертається клієнту. Response не обов’язково є прямою копією одного рядка: service може звертатися до іншої таблиці або зовнішньої системи, наприклад по taxId чи додаткові атрибути.

Поля на кшталт createdAt, updatedAt і deletedAt можуть зберігатися в базі, але не віддаватися назовні безпосередньо. DTO формує публічний контракт, а service відповідає за перетворення внутрішніх даних у цей контракт.

7:25

Перейменування полів і похідні значення

Навіть просте перейменування surname на lastName зачіпає кілька шарів: database/entity, зовнішній service, mapping і DTO. Якщо API має повертати fullName, service може формувати його з name та lastName; отже, механічне копіювання одного поля дасть синтаксично валідний, але семантично неправильний response.

Що більше полів і mapping rules, то вищий ризик пропустити зв’язок або зберегти не те значення. Тести мають перевіряти не лише наявність response, а й коректність значень після всіх перетворень.

Практика

Migration mapping checklist

  1. Оберіть одну DTO з проєкту.
  2. Для кожного field зафіксуйте source entity/service, mapping rule, nullability, required status, serializer behavior і regression test.
  3. Додайте один gateway header, який має пройти до внутрішнього service.

Результат: Mapping table і один перевірений routing contract.

11:41

Міграція моноліту в мікросервіси

Під час декомпозиції логіку, яка раніше жила в одному або кількох класах, переносять у різні services. Треба не лише перенести записи, а й зберегти правила зіставлення полів та джерела кожного значення.

Показано типовий регресійний ланцюжок: fullName випадково мапиться лише з lastName; локальний fix додає name, але дані все одно не оновлюються, бо справжнім джерелом був інший service. Так само похідний status може формуватися з timestamps лише на одному code path і залишитися null під час читання.

15:35

Чому перевірки лише status code недостатньо

Тест, який перевіряє тільки 200 OK, пропустить відсутнє поле, null, порожній рядок або неправильний mapping. Навіть перевірка переліку полів не гарантує правильного типу чи змісту.

Deserialization і schema validation дають дешевий базовий захист: response приводиться до строгої моделі, тому тест одразу виявляє відсутнє поле або неправильний тип. Для цього згадуються інструменти на кшталт Zod у TypeScript і Pydantic у Python. Окремо треба врахувати serializer settings: backend може зовсім вилучати з JSON поля зі значенням null.

Термін

OpenAPI Schema Object

OpenAPI 3.1 Schema Object описує структуру payload через JSON Schema vocabulary. Список required визначає обов’язкові properties; оголошення property саме по собі не робить його обов’язковим.

Термін

Pydantic strict mode

За замовчуванням Pydantic може перетворювати вхідні значення до потрібного типу. Strict mode зменшує coercion і повертає validation error, коли Python input має неправильний тип; правила для JSON input можуть відрізнятися для окремих типів.

Приклад коду

Strict validation для User DTO

from pydantic import BaseModel, ConfigDict, ValidationError

class UserDto(BaseModel):
    model_config = ConfigDict(strict=True, extra="forbid")
    id: int
    fullName: str
    status: str

valid = UserDto.model_validate({"id": 42, "fullName": "Ada Lovelace", "status": "active"})
assert valid.id == 42

for invalid in (
    {"id": "42", "fullName": "Ada Lovelace", "status": "active"},
    {"id": 42, "fullName": "Ada Lovelace"},
):
    try:
        UserDto.model_validate(invalid)
    except ValidationError:
        pass
    else:
        raise AssertionError(f"payload accepted unexpectedly: {invalid}")

Приклад відсікає coercion id із str у int, відсутній required field і невідомі extra fields.

Очікуваний результат: Valid payload приймається; два invalid payloads спричиняють ValidationError.

Потрібно: pydantic>=2,<3

18:42

Strict schema та negative behavior

Для критичних контрактів рекомендовано схилятися до strict validation: обов’язкове поле має бути присутнім і мати визначений тип. Щоб така перевірка була змістовною, test fixture треба створювати з повним набором даних, а не випадково залишати половину полів порожніми.

Генерація готових моделей прискорює роботу, але ручний red/green шлях іноді знаходить backend defects саме під час поступового заповнення й перевірки полів. Повністю «ідеальна» згенерована модель може приховати досвід негативних сценаріїв, хоча саме неочікувані дані часто відкривають проблеми.

22:55

Resource tests проти business-flow tests

Окремий resource test детально перевіряє schema, типи та mapping конкретної сутності. Business-flow test фокусується на ключових результатах і досяжності сценарію, не дублюючи кожну дрібну assertion з ресурсного рівня.

Частину детальних перевірок можна перенести на component/integration level, але лише якщо команда знає, що потрібний контракт там справді покритий і цим evidence можна довіряти. Інакше «це вже десь тестується» залишає реальну прогалину.

25:34

API gateway і внутрішні services

Клієнт звертається до одного зовнішнього API gateway, хоча за ним працюють окремі user/account та appointment services. Gateway перетворює зовнішній route і проксіює request у внутрішню мережу до відповідного service; зовнішнє й внутрішнє найменування ресурсу може відрізнятися.

Service, у свою чергу, може читати кілька tables, звертатися до інших services, виконувати filters і mappings, а controller повертає сформовану DTO. Тому response одного endpoint залежить не від одного методу, а від усього ланцюжка.

30:48

Routing-регресії та роль API tests

Під час міграції можна правильно перенести service, але помилитися в gateway route: не прокинути authorization header, body або інший обов’язковий параметр. Клієнт передасть credentials, gateway прийме request, а внутрішній service поверне 401, бо потрібний header загубився між ними.

API tests швидко виявляють такі дефекти mapping, schema й routing без довгого пошуку причини через UI. Практична стратегія сесії: окремо перевіряти контракт ресурсу, окремо — ключові business flows, а під час database чи infrastructure migration запускати обидва набори як regression coverage.

Джерела та додаткові матеріали

  • RFC 9110: HTTP Semantics ↗RFC Editor · перевірено 2026-07-31

    Уточнює значення 200 OK, 202 Accepted і response content для POST.

  • OpenAPI Specification v3.1.0 ↗OpenAPI Initiative · перевірено 2026-07-31

    Дає формальний contract для schema, types і required properties API payload.

  • Pydantic Strict Mode ↗Pydantic · перевірено 2026-07-31

    Пояснює runtime validation без небажаного type coercion.