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

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

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

0:00

Від `dict` до типізованої API-моделі

Замість того щоб працювати з response як із набором рядків і dictionary keys, пропонується описати його через Pydantic. Так тест перевіряє не лише наявність значення, а й структуру, типи та обов’язковість полів.

Джерелом схеми може бути OpenAPI-специфікація Testomat.io. Якщо документації немає, модель можна початково згенерувати з реального JSON через JSON-to-Pydantic і потім відредагувати. Автор одразу попереджає: навіть офіційна специфікація може відставати від фактичної response schema.

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

Pydantic validation не завжди є strict

АктуальноCurrent Pydantic v2 documentation states that input may be converted to declared types and extra fields are ignored by default. Якщо API-тест має виявляти будь-який schema drift, strict behavior і extra='forbid' треба задати явно.

Що змінилосяНе встановлено: точну Pydantic version у відео не названо.

Перевірено 2026-07-31

Термін

Pydantic model_validate()

Class method, який перевіряє вхідний object проти model schema і повертає model instance або піднімає ValidationError.

3:40

Генерація моделей з `OpenAPI`

До проєкту додаються pydantic і datamodel-code-generator. Генератор приймає локальну схему або URL, обирає Pydantic BaseModel як output і зберігає Python-моделі у src/api/models.

Довгу CLI-команду краще винести в project configuration: там фіксуються input, output, версія Python і правила aliases. Згенерований файл — це стартова точка, а не готова доменна модель: автоматичні назви і надто загальні класи ще доведеться уточнювати.

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

Генератору потрібно явно вказати Pydantic v2 output

АктуальноCurrent datamodel-code-generator docs recommend --output-model-type pydantic_v2.BaseModel for new Pydantic v2 projects; backward-compatible default pydantic.BaseModel targets v1. Для code з model_validate() output type треба фіксувати явно.

Що змінилосяНе встановлено: версію generator у відео не названо.

Перевірено 2026-07-31

Термін

datamodel-code-generator

Library і CLI utility, що генерує Pydantic-моделі з OpenAPI 3, JSON Schema та інших структурованих sources.

7:12

MVC як структура API-тестів

Показано спрощене застосування Model–View–Controller. Model описує DTO і response data; Controller інкапсулює запити; роль view у цьому тестовому контексті не розвивається.

Кожен REST resource — projects, suites, runs, templates, tests, users — отримує власний controller з потрібними операціями create, get, update, delete. Це тримає тестовий сценарій на рівні предметних дій, а URL, headers і розбір response залишаються в одному місці.

10:14

`BaseController`, headers, errors і logging

BaseController приймає base URL і JWT, формує спільні headers Authorization і Content-Type: application/json, виконує HTTP-запит і піднімає exception для неуспішного статусу. Методи get, post і put повторно використовують цю поведінку; post і put додатково приймають request body.

Запити варто логувати, щоб під час падіння було видно method, endpoint і контекст виклику. Для requests таке logging додають явно; HTTPX має власний logging namespace, тому конкретна реалізація залежить від обраного client.

13:19

Fixtures для авторизації і controllers

pytest fixtures виконують login, отримують JWT і передають його до ProjectController чи SuiteController. Якщо token вже збережено у scope fixture, нова авторизація не потрібна.

Для створення suite спершу потрібен target project. Його можна підготувати окремою fixture або отримати в самому тесті через ProjectController.get_all(). Вибір залежить від того, чи це спільний precondition, чи важливий крок конкретного сценарію.

17:00

Створення suite і реальний request contract

SuiteController.create() приймає project_id, title і description, формує payload та викликає post базового controller. Потрібні поля звіряються не лише з документацією, а й з request у browser DevTools. У демо офіційна схема містить сумнівну вимогу до suite_id до створення suite, тож real request і response виступають важливою перевіркою контракту.

Відповідь Testomat.io загортає основну сутність у поле data. Після response.json() тест бере response_data["data"] і валідує саме цю вкладену структуру.

Практика

Замкнути API-ланцюжок

  1. Створити suite у target project через SuiteController.
  2. Отримати створену сутність через API і провалідувати response Pydantic-моделлю.
  3. Повторити цей flow для test case через TestController.

Результат: Два API-тести проходять без UI-кроків і виявляють schema mismatch.

20:25

`model_validate()`, aliases і форма response

PydanticModel.model_validate(response_data["data"]) перетворює dictionary на типізований object і водночас перевіряє schema. Модель suite зводиться до реальних полів на кшталт id, type, attributes і relationships, а зайві generated wrappers видаляються.

Якщо JSON-ключ не є коректним Python-ідентифікатором, наприклад містить дефіс, для поля задається alias. У коді зберігається snake_case, а Pydantic зіставляє його з оригінальною назвою в JSON.

Термін

Field alias

Альтернативна назва field для validation чи serialization; дозволяє зіставити JSON-ключ із Python identifier.

Приклад коду

Валідація response field з alias

from pydantic import BaseModel, ConfigDict, Field

class SuiteAttributes(BaseModel):
    model_config = ConfigDict(extra="ignore")
    file_type: str = Field(alias="file-type")
    code: str | None = None

payload = {"file-type": "manual", "code": None, "ignored": "value"}
attributes = SuiteAttributes.model_validate(payload)
assert attributes.file_type == "manual"
assert attributes.code is None
print(attributes.model_dump())

Приклад показує model_validate(), JSON alias, nullable field і свідоме ігнорування зайвого response field.

Очікуваний результат: {'file_type': 'manual', 'code': None}

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

24:45

Перші падіння і діагностика fixtures

Згенерована models.py містить багато загальних класів на кшталт Attributes1, Attributes2, тому його краще використовувати як reference і поступово називати моделі за їхньою предметною роллю.

Під час демо тест падає через неправильні imports і видалену fixture. Для circular import корисно читати останній змістовний фрейм traceback: там зазвичай вказано реальний модуль і напрям залежності. Якщо pytest не знаходить fixture, він друкує перелік усіх доступних fixtures, що допомагає помітити назву або проблему з discovery.

31:05

Явна перевірка помилки типу

Щоб показати цінність schema validation, тип одного поля навмисно змінюється на str. Pydantic одразу повідомляє шлях до поля, очікуваний тип і фактичне None.

Якщо None справді дозволено контрактом, тип має це відображати, наприклад str | None. Any варто залишати лише для поля, структура якого справді нестабільна або не важлива для поточної перевірки.

33:10

Завдання: повний API-ланцюжок

Домашнє завдання — створити suite у вибраному project, отримати його через API і перевірити результат. Потім той самий підхід застосовується до test case: потрібно реалізувати TestController, request model, response model і перевірку створеної сутності.

Базові HTTP-методи, headers, error handling і logging перевикористовуються з BaseController. Якщо documentation schema неповна, спершу виконується реальний request, а його JSON response перетворюється на початкову Pydantic-модель. Помилки validation у цьому процесі допомагають поступово відтворити фактичний контракт.

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

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

    Точний contract model_validate(), ValidationError і model_dump().

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

    Пояснює alias, validation_alias і serialization_alias для зіставлення JSON з Python fields.

  • datamodel-code-generator ↗Pydantic · перевірено 2026-07-31

    Перелічує supported inputs і мінімальну CLI-команду генерації model.py.