По материалам открытых уроков и выступлений Светланы Лебедевой, старшего инженера по тестированию ПО и преподавателя 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