Pydantic-factry тестовых данных для генерация payload-ов
Project description
payforge
payforge – небольшая библиотека для QA-автотестов, которая помогает собирать тестовые payload-ы на базе Pydantic-моделей.
Идея простая: одна модель описывает структуру запроса. По ней можно собрать payload для API, точечно переопределить нужные поля, сломать данные для негативного теста и этой же моделью проверить ответ.
Установка
pip install payforge
Из обязательных зависимостей – только pydantic>=2.
Генераторы случайных данных, например Faker, библиотека не подтягивает. Их можно подключить отдельно, если они нужны в проекте.
Быстрый старт
from payforge import DataFactory, FactoryModel
from pydantic import Field
class Config(FactoryModel):
token: str = "default-token"
timeout: int = 30
class Webhook(FactoryModel):
list_id: str = Field("L-1", alias="list") # API ждёт ключ "list"
config: Config = Field(default_factory=Config)
class WebhookFactory(DataFactory):
pass
f = WebhookFactory()
# Собрать валидный payload:
f.build(Webhook)
# {"list": "L-1", "config": {"token": "default-token", "timeout": 30}}
# Переопределить вложенное поле:
f.build(Webhook, **{"config.token": "secret"})
# {"list": "L-1", "config": {"token": "secret", "timeout": 30}}
# Собрать payload для негативного теста:
f.build_invalid(Webhook, field="config.timeout", value="not-a-number")
# Собрать несколько payload-ов:
f.build_many(Webhook, count=3, each=lambda i: {"config.token": f"tok-{i}"})
# [{...tok-0...}, {...tok-1...}, {...tok-2...}]
# Получить типизированный экземпляр модели:
wh = f.build_model(Webhook)
# Проверить ответ API той же моделью:
f.validate(Webhook, api_response)
# -> Webhook | SchemaValidationError
Случайные значения
payforge специально не зависит от Faker или других генераторов данных. Так библиотека остаётся лёгкой, а проект сам решает, чем генерировать тестовые значения.
Например, Faker можно подключить через default_factory:
from faker import Faker
from pydantic import Field
fake = Faker()
class User(FactoryModel):
name: str = Field(default_factory=fake.name)
email: str = Field(default_factory=fake.email)
Как пользоваться
Модель можно передать классом или строкой
Все основные методы принимают entity:
- класс Pydantic-модели, например
Webhook; - строковый ключ из
entities, если хочется вызывать фабрику по имени.
Рекомендуемый вариант – передавать сам класс модели. Так не нужен реестр, а IDE лучше понимает типы, особенно при использовании build_model().
f.build(Webhook)
Если удобнее обращаться к моделям по строковым ключам, можно объявить entities:
class WebhookFactory(DataFactory):
entities = {
"webhook": Webhook,
}
WebhookFactory().build("webhook")
Если строковый ключ неизвестен или реестр не объявлен, будет выброшена ошибка UnknownEntityError.
Валидация и негативные тесты
По умолчанию build() собирает payload и прогоняет его через модель.
f.build(Webhook)
Это поведение соответствует validate=True.
Если в overrides передать значение неподходящего типа, Pydantic выбросит ValidationError.
f.build(Webhook, **{"config.timeout": "not-a-number"})
# pydantic.ValidationError
Для негативных тестов можно отключить повторную валидацию:
f.build(
Webhook,
validate=False,
**{"config.timeout": "not-a-number"},
)
В этом режиме фабрика сначала собирает валидную базу из дефолтов модели, а потом аккуратно накладывает переопределения поверх неё. Соседние поля при этом не теряются.
Важно: для validate=False модель должна уметь создаваться без аргументов. То есть у всех обязательных полей должны быть значения по умолчанию или default_factory.
build_invalid
build_invalid() – короткий способ собрать payload для негативного теста.
f.build_invalid(
Webhook,
field="config.timeout",
value="not-a-number",
)
Под капотом это валидная база плюс одно испорченное поле. Значение из field накладывается последним, поэтому оно перебивает остальные overrides, если есть конфликт.
Несколько payload-ов
Метод build_many() собирает список payload-ов.
f.build_many(Webhook, count=10)
Общие значения можно передать как обычные overrides – они применятся ко всем элементам:
f.build_many(Webhook, count=3, list_id="SHARED")
Если каждому элементу нужны свои значения, используйте each:
f.build_many(
Webhook,
count=3,
each=lambda i: {"config.token": f"tok-{i}"},
)
Можно сочетать общий override и индивидуальные значения:
f.build_many(
Webhook,
count=2,
list_id="SHARED",
each=lambda i: {"list": f"L{i}"},
)
Если одно и то же поле задано и в общих overrides, и в each, победит значение из each.
Особенности:
count=0вернёт пустой список;- отрицательный
countвыброситValueError; - параметры
validate,exclude_noneиby_aliasпробрасываются вbuild().
Вложенные поля и alias-ы
Поля можно переопределять по имени поля модели или по alias-у.
Для вложенных моделей используется dotted-path:
f.build(Webhook, **{"config.token": "x"})
Так меняется только config.token, а остальные поля внутри config остаются на месте.
Сериализация по умолчанию идёт с by_alias=True, поэтому поле:
list_id: str = Field("L-1", alias="list")
попадёт в payload как:
{"list": "L-1"}
Это же учитывается и в негативных сценариях. Если переопределить поле по имени list_id, в итоговом payload всё равно будет ключ list, а не два разных ключа list и list_id.
Валидация ответа API
Ответ API можно проверить той же моделью:
result = f.validate(Webhook, api_response)
Если ответ подходит под схему, метод вернёт экземпляр модели.
Если данные не прошли валидацию, будет выброшена SchemaValidationError. В поле .errors лежит структурированный список ошибок Pydantic.
Ошибки
payforge использует свои ошибки там, где нужно отделить ошибки фабрики от обычных ошибок Pydantic.
UnknownEntityError
Возникает, если в фабрику передали строковый ключ, которого нет в entities, или если реестр entities не объявлен.
f.build("unknown")
SchemaValidationError
Возникает при проверке ответа API через validate(), если ответ не соответствует модели.
try:
f.validate(Webhook, api_response)
except SchemaValidationError as e:
print(e.errors)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file payforge-0.1.0.tar.gz.
File metadata
- Download URL: payforge-0.1.0.tar.gz
- Upload date:
- Size: 10.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2156338e2dd4b2d7226528f1339bcf53b13ac6a3bda445c2a5988ae16ce5da54
|
|
| MD5 |
835c1045628b49f449fc6c93a6de46a8
|
|
| BLAKE2b-256 |
e2e3dd495278e71533248ea0dabd655b9a8d03b335a1e5f55b1fc9ceeb856d30
|
Provenance
The following attestation bundles were made for payforge-0.1.0.tar.gz:
Publisher:
publish.yml on TheGreatPepix/payforge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
payforge-0.1.0.tar.gz -
Subject digest:
2156338e2dd4b2d7226528f1339bcf53b13ac6a3bda445c2a5988ae16ce5da54 - Sigstore transparency entry: 1936543353
- Sigstore integration time:
-
Permalink:
TheGreatPepix/payforge@17c535211d15857030352f095fc744db77b67dd9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/TheGreatPepix
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@17c535211d15857030352f095fc744db77b67dd9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file payforge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: payforge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 10.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82abe4cd1dc815df7bcf17188f492e54dbb410e6de63d930f8d7c3e5f8529d5c
|
|
| MD5 |
3507a2f0f5ea2259a9156cb1df01c3bb
|
|
| BLAKE2b-256 |
8e64a4606db0716aad8f26b3b777a5ea81830bf087a5d90192d941cf3e094abb
|
Provenance
The following attestation bundles were made for payforge-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on TheGreatPepix/payforge
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
payforge-0.1.0-py3-none-any.whl -
Subject digest:
82abe4cd1dc815df7bcf17188f492e54dbb410e6de63d930f8d7c3e5f8529d5c - Sigstore transparency entry: 1936543386
- Sigstore integration time:
-
Permalink:
TheGreatPepix/payforge@17c535211d15857030352f095fc744db77b67dd9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/TheGreatPepix
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@17c535211d15857030352f095fc744db77b67dd9 -
Trigger Event:
push
-
Statement type: