Протестировать свой сервис на данных, похожих на настоящие, помогают специальные библиотеки Faker и Pydantic. Рассказываем, как их установить и для каких задач использовать.
Что такое библиотека Faker и для чего она нужна
Во время разработки и тестирования приложения на Python, когда уже есть структура или API, часто нужен набор данных, похожих на реальные. Это могут быть списки пользователей, заказов или email-адресов. Использовать настоящие персональные данные небезопасно, а создавать десятки и сотни записей вручную долго. Поэтому разработчики используют библиотеку Faker.

Faker генерирует реалистичные имена, адреса, даты, номера телефонов. Ими можно заполнять локальные базы данных, проверять работу API, а также использовать их в автоматических тестах и при демонстрации работы приложения.
Для отдельных значений Faker можно настроить ограничения: выбрать locale (локаль), задать диапазон возраста или чисел и период для дат, а также использовать собственные провайдеры (наборы методов). Так тестовые данные будут ближе к требованиям проекта.
Но Faker не знает структуру и бизнес-правила вашего проекта. Например, сам он не поймет, что пользователи в списке должны быть старше 18 лет или что email-адрес должен относиться к конкретному домену. Поэтому после генерации данных их нужно проверить на соответствие правилам приложения.
Как проверять входные данные
Этот вопрос относится не только к сгенерированным, но и к любым другим данным, которые приложение получает извне.
Например, наше приложение получило JSON-запрос из API, значения из формы или переменные окружения. Да, мы можем валидировать данные вручную, но только если данных немного, а требования к ним простые.
Если же появляется много дополнительных условий, то приходится искать, как это сделать быстро.
В помощь разработчикам Самуэль Колвин создал библиотеку Pydantic. Она позволяет задавать ожидаемую структуру данных, проверять значения и создавать модель с проверенными значениями и ожидаемыми типами. Например, Pydantic может преобразовать строку в число, а при недопустимом значении вернуть ошибку валидации.

Генерируем данные с Faker
Выше мы уже разобрались, что Faker — это библиотека для генерации данных, похожих на реальные. Она работает через провайдеров или наборы методов для разных категорий данных: имен, адресов, дат или банковских реквизитов.
Метод name() создает имя, email() — адрес электронной почты, а date_between() возвращает случайную дату из заданного периода.
Faker также поддерживает локализованные провайдеры. Поэтому для разных регионов можно получить соответствующие имена, адреса и номера телефонов — нужно только указать локаль.
Как установить Faker
Сначала установите библиотеку в активное виртуальное окружение проекта. Так Faker будет доступен только в зависимостях конкретного приложения, а не во всех программах, запущенных через Python:
python -m pip install Faker
Установить пакет в глобальную среду Python тоже можно, но вы рискуете наткнуться на проблему с зависимостями, когда обновление библиотеки для одного проекта может нарушить работу другого.
После установки импортируйте класс Faker:
from faker import Faker
Затем создайте объект генератора:
fake = Faker()
Теперь вы сможете вызывать методы для получения тестовых значений, к которым относятся:
- имена;
print(fake.name())
- адреса электронной почты;
print(fake.email())
- номера телефонов;
print(fake.phone_number())
- адреса с городом, улицей и почтовым индексом.
print(fake.address())
При каждом вызове метода Faker генерирует случайное значение. В разных вызовах значения могут отличаться, но повторы тоже возможны.
Как указать локаль в Faker
По умолчанию Faker использует локаль en_US, поэтому он генерирует данные в американском формате. Чтобы получить значения другого региона, при создании объекта Faker нужно передать код locale в формате язык_регион.
Например, для русскоязычных имен, адресов и названий городов используют локаль ru_RU:
from faker import Faker
fake = Faker("ru_RU")
print(fake.name())
print(fake.city())
print(fake.address())
print(fake.phone_number())
Запустим пример в Online Faker Compiler с предустановленным Faker и получим сгенерированные данные.

Как сгенерировать карточку пользователя и задать правила в Faker
Faker можно использовать для генерации записи с несколькими полями — например, для создания карточки пользователя. Чтобы хранить полученные данные, мы используем словарь.
Также прямо в генераторе мы можем задать ограничения по возрасту и дате регистрации. Для этого применим метод random_int(), который возвращает число из указанного диапазона, а также date_between(), который возвращает дату в заданном интервале.
from faker import Faker
fake = Faker("ru_RU")
user_data = {
"full_name": fake.name(),
"email": fake.email(),
"phone": fake.phone_number(),
"city": fake.city(),
"age": fake.random_int(min=18, max=70),
"registered_at": fake.date_between(
start_date="-2y",
end_date="today",
).isoformat(),
}
print(user_data)
В результате мы получим словарь с вымышленным набором данных:

Как генерировать значения из заданного списка в Faker
Не все поля должны содержать произвольные данные. Например, статус заказа может принимать только несколько заранее определенных значений вроде new, paid, shipped или cancelled. Генератор не должен создавать другие статусы, иначе приложение их не распознает.
Для таких случаев в Faker есть метод random_element(). В него передают список допустимых вариантов, а он случайно выбирает один из них:
from faker import Faker
fake = Faker()
order_status = fake.random_element(
elements=("new", "paid", "shipped", "cancelled")
)
print(order_status)
Получим:

Как сделать данные воспроизводимыми в Faker
Набор значений можно сделать одинаковым при каждом запуске. Для этого генератору нужно задать начальное значение.
Для отдельного объекта Faker используем метод seed_instance(). Он фиксирует последовательность данных только для этого генератора и не влияет на другие объекты Faker в проекте:
from faker import Faker
fake = Faker("ru_RU")
fake.seed_instance(42)
print(fake.name())
print(fake.email())
Получим:

Если при нескольких запусках указаны одна и та же версия Faker, одна и та же локаль, одно и то же значение seed (начальное значение) и тот же порядок вызова методов, то результат будет одним и тем же.
Если нужно задать общее начальное значение для всех создаваемых объектов Faker, то можно использовать метод класса Faker.seed():
from faker import Faker
Faker.seed(42)
first_fake = Faker("ru_RU")
second_fake = Faker("en_US")
Тут мы создали два генератора — first_fake и second_fake. Проверим их работу, вызвав name():
print(first_fake.name()) print(second_fake.name())
Получим:

Но важно понимать, что методы с относительными датами, например date_between(start_date=»-2y», end_date=»today»), могут дать иной результат при запуске в другой день, потому что границы интервала зависят от текущей даты. Если хотите получить стабильную генерацию, то нужно указывать конкретные даты.
Валидируем и приводим данные к нужному типу с Pydantic
Библиотека Pydantic позволяет валидировать входные данные. С ней можно описать ожидаемую структуру объекта с помощью аннотаций типов.
Например, в наше приложение отправили JSON-запрос с данными пользователя. Pydantic проверит, есть ли в нем обязательные поля, попробует привести значения к нужным типам и сообщит об ошибке, если это сделать не получится.
Как установить Pydantic
Принцип такой же, как и для Faker. Устанавливаем библиотеку в активное виртуальное окружение проекта:
python -m pip install pydantic
После установки класс BaseModel и другие компоненты Pydantic можно импортировать в код проекта.
Как создать модель с Pydantic BaseModel
Создадим модель пользователя с использованием класса BaseModel. В ней укажем, что id и age должны быть целыми числами, full_name и email — строками, а registered_at — датой:
from datetime import date from pydantic import BaseModel class User(BaseModel): id: int full_name: str email: str age: int registered_at: date
После определения полей и ожидаемых типов в эту модель можно передавать словарь. Его мы сгенерируем с помощью Faker.
Словарь user_data у нас будет содержать сгенерированную информацию о пользователе.
user_data = {
"id": "1",
"full_name": "Александр Смирнов",
"email": "alexander.smirnov@example.org",
"age": "34",
"registered_at": "2025-08-14",
}
user = User(**user_data)
print(user)
Оператор ** распакует словарь user_data в именованные аргументы. Pydantic создаст объект:
id=1 full_name='Александр Смирнов' email='alexander.smirnov@example.org' age=34 registered_at=datetime.date(2025, 8, 14)
Обратите внимание, что в исходном словаре id и age были строками, а в модели они стали числами. Значение registered_at тоже преобразовалось из строки в объект date.
Вы всегда можете провести проверку типов:
print(type(user.id)) print(type(user.age)) print(type(user.registered_at))
И получить вывод в консоли:
<class 'int'> <class 'int'> <class 'datetime.date'>
У Pydantic также есть «строгий режим» (strict mode), в котором автоматическое преобразование типов ограничено. Например, при передаче Python-словаря строка «34» не преобразуется в число для поля age: int и вызовет ошибку валидации.
Что будет, если данные окажутся некорректными
Заменим возраст на текстовую строку, которую нельзя преобразовать в целое число:
invalid_user_data = {
"id": "1",
"full_name": "Александр Смирнов",
"email": "alexander.smirnov@example.org",
"age": "тридцать четыре",
"registered_at": "2025-08-14",
}
user = User(**invalid_user_data)
Тогда при создании модели мы получим исключение ValidationError.

В сообщении будет указано поле, в котором возникла проблема:
pydantic_core._pydantic_core.ValidationError: 1 validation error for User age Input should be a valid integer, unable to parse string as an integer
Какие ограничения есть в Pydantic Field
Кроме типа данных (строка, число и так далее), в Pydantic можно валидировать и другие параметры, например количество символов в строке или диапазон значений.
Для таких ограничений используют функцию Field(). Она позволяет:
- задать ограничения;
- указать значение по умолчанию;
- добавить описание и примеры для документации.
Создадим модель товара:
from pydantic import BaseModel, Field
class Product(BaseModel):
name: str = Field(
min_length=2,
max_length=100,
description="Название товара",
examples=["Беспроводная мышь"],
)
price: float = Field(
gt=0,
description="Цена товара в рублях",
examples=[1599.90],
)
quantity: int = Field(default=0, ge=0)
model: str = Field(
pattern=r"^[A-Z]{2}-\d{4}$",
description="Артикул в формате AB-1234",
examples=["EL-1024"],
)
Field() задает такие ограничения для полей:
| min_length | минимальная длина строки | name: str = Field(min_length=2) |
| max_length | максимальная длина строки | name: str = Field(max_length=100) |
| gt | значение должно быть строго больше указанного | price: float = Field(gt=0) |
| ge | значение должно быть больше или равно указанному | quantity: int = Field(ge=0) |
| pattern | Соответствие регулярному выражению | model: str = Field(pattern=…) |
Создадим модель:
product = Product( name="Беспроводная мышь", price=1599.90, quantity=12, model="EL-1024" ) print(product)
Получим объект:
name='Беспроводная мышь' price=1599.9 quantity=12 model='EL-1024'
А вот такая модель не пройдет проверку:
invalid_product = Product( name="М", price=0, quantity=-3, model="мышь-1", )
Получим ошибку:

Pydantic сообщит, что:
- значение name слишком короткое;
- price должно быть больше нуля;
- quantity не может быть отрицательным;
- model не соответствует формату AB-1234.
Как работают обязательные поля и значения по умолчанию
Поля можно сделать необязательными. Для этого указывают значение поля по умолчанию.
Например, тут поле name обязательно:
name: str = Field(min_length=2, max_length=100)
Но если есть default-значение, то поле можно не указывать:
quantity: int = Field(default=0, ge=0)
То есть если при создании товара не передать quantity, Pydantic поставит 0.
Бывает так, что значение по умолчанию нельзя записать заранее, когда, например, для каждого нового заказа нужен свой пустой список товаров, а для каждой новой записи — уникальный идентификатор.
Тогда используют default_factory, чтобы Pydantic вызывал указанную функцию при создании каждой модели.
from uuid import uuid4 from pydantic import BaseModel, Field class Order(BaseModel): id: str = Field(default_factory=lambda: uuid4().hex) items: list[str] = Field(default_factory=list) order = Order() print(order.id) print(order.items)
Теперь при создании нового заказа сгенерируется уникальный id и появится отдельный пустой список items:

Описание и примеры поля
Отдельно стоит упомянуть description и examples — это параметры, которые встречались в предыдущих примерах в Field(). Поле description описывает назначение поля, а examples показывает ожидаемое значение. Это нужно для отображения в документации.
Например:
price: float = Field( gt=0, description="Цена товара в рублях", examples=[1599.90], )
Когда Field() не поможет
Field() не предназначен для проверки правил, которые зависят сразу от нескольких полей.
Например, нельзя описать через Field(), что дата окончания подписки должна быть позже даты начала:
from datetime import date from pydantic import BaseModel class Subscription(BaseModel): start_date: date end_date: date
Оба значения могут быть корректными датами по отдельности, но вместе образовать неверную запись:
Subscription( start_date="2026-06-20", end_date="2026-06-10", )
Field() не может сравнить их между собой. Для таких случаев нужно использовать валидатор Pydantic.
Как создать сложные правила проверки с помощью валидаторов Pydantic
В Pydantic (v2) для сложных условий проверки используют декораторы @field_validator и @model_validator.
- Для проверки одного поля — @field_validator.
Создадим правило: имя пользователя не должно содержать пробелы.
from pydantic import BaseModel, field_validator
class RegistrationData(BaseModel):
username: str
password: str
@field_validator("username")
@classmethod
def username_must_not_contain_spaces(cls, value: str) -> str:
if " " in value:
raise ValueError(
"Имя пользователя не должно содержать пробелы"
)
return value
Такая запись пройдет проверку:
user = RegistrationData( username="anna_smith", password="qwerty123", )
А такая не пройдет:
user = RegistrationData( username="anna smith", password="qwerty123", )
Все потому, что когда валидатор получает значение поля username, он ищет в нем пробел. Если пробел найден, функция вызывает ValueError. Pydantic преобразует ее в ошибку валидации и не создает объект RegistrationData.
- Для проверки нескольких полей — @model_validator.
С помощью @model_validator можно провалидировать всю модель:
from datetime import date from pydantic import BaseModel, model_validator class Subscription(BaseModel): start_date: date end_date: date @model_validator(mode="after") def end_date_must_be_after_start_date(self): if self.end_date <= self.start_date: raise ValueError( "Дата окончания должна быть позже даты начала" ) return self
Тогда наконец мы сможем проверять даты по критерию «начальная должна быть раньше конечной». Эта запись пройдет проверку:
Subscription( start_date="2026-06-10", end_date="2026-06-20", )
А эта не пройдет:
Subscription( start_date="2026-06-20", end_date="2026-06-10", )
Как преобразовать модель Pydantic в словарь или JSON
Модель Pydantic зачастую нужно передать в другую функцию, сохранить в базу или вернуть из API. Для этого модель преобразуют в словарь или JSON-строку.
Основной метод для получения словаря называется model_dump():
from datetime import date from pydantic import BaseModel class UserProfile(BaseModel): id: int full_name: str email: str password_hash: str middle_name: str | None = None newsletter: bool = False registered_at: date user = UserProfile( id=1, full_name="Александр Смирнов", email="alexander.smirnov@example.org", password_hash="hashed-password", registered_at="2026-06-20", ) user_data = user.model_dump() print(user_data)
Так мы получим словарь:
{
"id": 1,
"full_name": "Александр Смирнов",
"email": "alexander.smirnov@example.org",
"password_hash": "hashed-password",
"middle_name": None,
"newsletter": False,
"registered_at": datetime.date(2026, 6, 20),
}
Для получения JSON используют model_dump_json():
json_data = user.model_dump_json() print(json_data)
В результате получим строку в формате JSON:
{"id":1,"full_name":"Александр Смирнов","email":"alexander.smirnov@example.org","password_hash":"hashed-password","middle_name":null,"newsletter":false,"registered_at":"2026-06-20"}
Как модели Pydantic работают в API
FastAPI использует Pydantic-модели при работе с запросами и ответами API.
Сначала клиент отправляет JSON-запрос, затем FastAPI проверяет его по модели Pydantic. После этого функция получает уже проверенные данные.
Например, клиент создает пользователя. В запросе он передает имя, email и пароль. Для получения этих данных создадим модель UserCreate.
Для проверки формата email нужен тип EmailStr. Он использует дополнительную зависимость email-validator, поэтому установим FastAPI и дополнительную зависимость Pydantic для проверки email:
python -m pip install fastapi "pydantic[email]"
Теперь создадим две модели:
from fastapi import FastAPI from pydantic import BaseModel, EmailStr app = FastAPI() class UserCreate(BaseModel): full_name: str email: EmailStr password: str class UserResponse(BaseModel): id: int full_name: str email: EmailStr
- UserCreate описывает данные, которые клиент отправляет при регистрации.
- UserResponse описывает данные, которые клиент получит в ответ. Пароля в ней нет, потому что возвращать его клиенту не нужно.
Добавим обработчик запроса — эндпоинт:
@app.post("/users", response_model=UserResponse)
def create_user(user: UserCreate):
internal_user = {
"id": 1,
"full_name": user.full_name,
"email": user.email,
"password_hash": "hashed-password",
"is_admin": False,
}
return internal_user
Когда клиент отправит запрос POST /users, FastAPI сначала проверит его по модели UserCreate. Например, если в запросе нет full_name или указан некорректный email, API вернет ошибку валидации и не запустит функцию create_user().
Если данные корректны, то FastAPI создаст объект user и передаст его в функцию. Внутри функции мы формируем словарь internal_user, который содержит и внутренние данные — password_hash и is_admin.
Параметр response_model = UserResponse указывает, какие поля можно отправить клиенту. FastAPI возьмет из internal_user только поля, описанные в UserResponse:
{
"id": 1,
"full_name": "Александр Смирнов",
"email": "alexander.smirnov@example.org"
}
Поля password_hash и is_admin в ответ не попадут. Таким образом, Pydantic-модели в FastAPI помогают проверить входящий запрос и при этом не раскрывать внутренние данные в ответе API.
