генерация и валидация тестовых данных OTUS
2026-03-10 02:23 Diff

По материалам открытых уроков и выступлений Светланы Лебедевой, старшего инженера по тестированию ПО и преподавателя OTUS

Датаклассы в Python

Словари и дата-классы
Перед тем как перейти к обзору библиотек, рассмотрим различия словарей и датаклассов.

Словарь (dictionary): структура данных, которая позволяет хранить пары «ключ-значение». Ключ – неизменяемый тип данных, обычно – строка, но ключом может быть и целое число, число с точкой или даже «кортеж». Данные из словаря мы извлекаем по ключу. Скажем сразу: в этой статье речь идёт о базовом словаре (dict), а не о более продвинутой структуре данных TypedDict. 

Обычно инженеры по автоматизации тестирования работают со структурой JSON, которая проще всего конвертируется в обычный dict. У dict нет чёткой структуры и валидации типов данных; значения могут быть самых разных типов: как изменяемых, так и неизменяемых, и при инициализации словаря мы не можем задать ограничения по добавляемым в него типам данным. 

Датаклассы: сравнительно новая фича в Python. Как видно из названия, эти классы представляют набор инструментов для хранения и обработки данных.

Вот основные отличия датаклассов от обычных классов:

  • При использовании датаклассов не нужно думать о методе __init__ (метод, который вызывается при создании объекта класса).
  • Не нужно думать о методах, которые позволяют сравнивать два объекта одного класса.
  • Код становится чище и красивее.
  • Чтобы создать датакласс, нужно просто использовать декоратор @dataclass.
  • Есть метод __post_init__, который позволяет добавить данные уже после инициализации объекта этого класса.

Модуль dataclasses также включает в себя функцию field, которая позволяет более гибко настраивать поля датаклассов. С помощью field можно задавать параметры по умолчанию, функции для создания значений по умолчанию (или «фабрики») и параметры, которые влияют на генерацию методов.

Пример использования датакласса и функции field: 

from dataclasses import dataclass, field from typing import List @dataclass class Student:    name: str    age: int    grades: List[int] = field(default_factory=list)

Здесь мы создаём класс для хранения данных ученика, где поле grades по умолчанию – пустой список. 

Для валидации данных в датаклассах можно использовать метод __post_init__, который вызывается сразу после генерации __init__. Это позволяет выполнять дополнительную логику. Например, проверку типов и значений:

from dataclasses import dataclass, field @dataclass class Product:    name: str    price: float    quantity: int = field(default=0)    def __post_init__(self):        if self.price <= 0:            raise ValueError("Цена должна быть больше 0")        if self.quantity < 0:            raise ValueError("Количество должно быть больше 0") # Правильное использование product = Product(name="Laptop", price=1000.0, quantity=5) # Неправильное использование вызовет исключение try:    product_with_negative_price = Product(name="Laptop", price=-1000.0) except ValueError as e:    print(e)  # Цена должна быть больше 0

Библиотеки Faker и Pydantic упрощают процесс валидации и генерации данных, а потому – очень полезны в процессе автоматизации тестирования.

Функционал библиотеки Pydantic

Pydantic – библиотека, в основе которой лежит концепция датаклассов или «моделей». Библиотека позволяет удобно хранить и валидировать данные прямо в момент создания объекта класса. Кроме того, в Pydantic можно превращать данные, как из модели данных – в JSON, так и наоборот: из JSON – в модель данных. 

Pydantic широко используется не только в автоматизированном тестировании, но и в бэкенд-разработке для валидации данных с сервера.  Поэтому у Pydantic огромное сообщество: всегда найдётся кто-то, кто поможет вам решить вопрос.

Возможности Pydantic

Поддержка аннотаций типов: в Pydantic можно управлять валидацией схем и сериализацией. Это упрощает изучение, уменьшает количество кода и обеспечивает  интеграцию с IDE.

Скорость: логика валидации Pydantic написана на Rust. Поэтому Pydantic – одна из самых быстрых библиотек для валидации данных в Python.

JSON Schema: модели Pydantic могут генерировать JSON Schema, что облегчает интеграцию с другими инструментами.

Строгий и гибкий режимы: Pydantic может работать в строгом режиме (strict=True), где данные не преобразуются, или в гибком режиме (strict=False), где Pydentic при необходимости пытается привести данные к правильному типу.

Настройка: Pydantic позволяет применять пользовательские валидаторы и сериализаторы для изменения обработки данных разными способами.

Экосистема: около 8000 пакетов на PyPI используют Pydantic.

Распространение: Pydantic скачивается более 70 миллионов раз в месяц; используется всеми компаниями FAANG и 20 из 25 крупнейших компаний NASDAQ

Подробнее о возможностях библиотеки Pydantic: смотреть фрагмент конференции «OTUS CONF: Тестирование» 

Недостатки 

  • Не входит в стандартную библиотеку Python
  • Требует много времени на освоение из-за обширной документации

Чтобы использовать модель Pydantic, достаточно «унаследовать» новый класс от класса BaseModel, после чего обширный функционал библиотеки станет доступен. 

Пример:

from pydantic import BaseModel, Field, field_validator from typing import List class Product(BaseModel):    name: str    price: float = Field(..., gt=0, description="Price must be greater than zero")    quantity: int = Field(default=0, ge=0, description="Quantity must be greater than zero")    tags: List[str] = []    @field_validator('name')    @classmethod    def name_must_not_be_empty(cls, v):        if not v.strip():            raise ValueError('Name must not be empty')        return v    @field_validator('tags')    @classmethod    def tags_must_be_non_empty(cls, v):        if not v:            raise ValueError('Tags must not be empty')        return v # Правильное использование try:    product = Product(name="Laptop", price=1000.0, quantity=5, tags=["electronics", "computers"])    print(product) except ValueError as e:    print(e) # Неправильное использование вызовет исключение try:    invalid_product = Product(name="  ", price=-1000.0, quantity=-1, tags=[]) except ValueError as e:    print(e)

В этом примере:

  • Класс Product наследуется от BaseModel Pydantic.
  • Поля price и quantity используют встроенные валидаторы gt (greater than) и ge (greater or equal) для проверки значений.
  • Пользовательский валидатор для поля name проверяет, что имя не пустое.
  • Пользовательский валидатор для поля tags проверяет, что каждый тег не пустой.

Функционал библиотеки Faker

Faker – библиотека, которая генерирует реалистичные тестовые данные с разной локализацией. У этой библиотеки много провайдеров: провайдер адреса, провайдер номеров автомобилей, банковской информации, штрихкодов, эмоджи, текстовый провайдер, провайдер для генерации географических данных и проч.

Также у Faker много локализаций с данными, специфичными для конкретной страны.

Формат JSON

Часто в проекте нужно сгенерировать какой-то JSON, который должен содержать данные о пользователе. И вам приходится придумывать фамилию, имя, отчество, номер карты, адрес, email. Чтобы не тратить время, вы можете сделать всё это с помощью библиотеки Faker. Кроме того, с помощью Faker можно наполнять базы данных и делать тестовые файлы.

Подробнее про использование Faker: смотреть запись вебинара на Youtube

Faker легко установить и использовать

->стандартная команда !pip install Faker  Пишем код с использованием Faker: from faker import Faker faker = Faker() print(f'name: {faker.name()}')  # name: Arthur Patton print(f'address: {faker.address()}')  # address: 0638 Larsen Way, Tylermouth, CA 48344 print(f'text: {faker.sentence()}')  # text: While per budget up technology design.

Теперь объединим две библиотеки, чтобы сгенерировать простой JSON-объект:

from pydantic import BaseModel, Field from faker import Faker from typing import List # Инициализация Faker faker = Faker() # Функции для генерации данных с помощью Faker def fake_name():    return faker.name() def fake_age():    return faker.random_int(min=18, max=25) def fake_grades():    return [faker.random_int(min=60, max=100) for _ in range(5)] # Определение модели данных с использованием Pydantic class Student(BaseModel):    name: str = Field(default_factory=fake_name)    age: int = Field(default_factory=fake_age)    grades: List[int] = Field(default_factory=fake_grades) # Создание экземпляра модели Student с автоматической генерацией данных и их валидация try:    student = Student()    print(student) except ValueError as e:    print(e) # Конвертация объекта Pydantic в JSON student_json = student.model_dump() print(student_json) >>> {'name': 'Maria Riddle', 'age': 23, 'grades': [81, 87, 74, 92, 92]}

Дополнительно

  • В качестве функции-аргумента для default_factory нужно использовать функцию, не принимающую аргументы. Если аргументы всё-таки нужно передать, можно воспользоваться lambda-функцией. Например: Field(default_factory=lambda: faker.random_int(min=60, max=100))
  • Датакласс можно превратить в словарь с помощью функции asdict. В модели Pydantic для этого используется метод model_dump()
  • Faker и Pydantic не входят в стандартный пакет Python

Больше о полезных библиотеках для автоматизации тестирования – на курсе Python QA Engineer