Генерация данных для тестирования на Python

Раздел: Тестирование -> Тестирование

Создание тестовых данных в Python: методы и примеры

Как эффективно генерировать реалистичные тестовые данные с помощью Faker?

Библиотека Faker является наиболее популярным и мощным инструментом для генерации тестовых данных на Python. Она поддерживает множество локалей, типов данных и легко расширяется.


# Установка: pip install faker
from faker import Faker

fake = Faker('ru_RU')  # русская локаль

# Генерация простых данных
print(fake.name())
print(fake.address())
print(fake.email())
print(fake.phone_number())
  

A b test python (a/b тестирование в python)

Сидоров Андрей Петрович
ул. Ленина, д. 5, кв. 10, г. Москва, 101000
sidorov@example.com
+7 (495) 123-45-67
  

тесты алгоритмы и программирование python (тестирование алгоритмов и программ на python)

Для создания массива данных используется цикл или генератор:


users = []
for _ in range(5):
    user = {
        'name': fake.name(),
        'email': fake.unique.email(),  # уникальные email
        'birth_date': fake.date_of_birth(minimum_age=18, maximum_age=70)
    }
    users.append(user)
print(users)
  

Python code tests (тестирование кода в python)

Faker позволяет генерировать почти любые типы: текст, числа, даты, адреса, компании, банковские данные и т.д.

Типичные проблемы и их решения:

  • Неуникальность данных - используйте fake.unique.field() (например, fake.unique.email()), но следите, что количество уникальных значений не превышает возможностей генератора. Альтернатива: добавить индекс или случайный суффикс.
  • Низкая производительность при миллионах записей - создавайте данные пакетами, используйте batch() или генерацию в отдельном процессе.
  • Зависимость от внешней библиотеки - для CI/CD или автономного использования можно кешировать сгенерированные данные или использовать встроенный модуль random.

Как сгенерировать простые тестовые данные без внешних библиотек?

Модуль random и string из стандартной библиотеки позволяют быстро создать примитивные данные, но они менее реалистичны.


import random
import string

def random_email():
    domains = ['test.com', 'example.org', 'demo.net']
    name = ''.join(random.choices(string.ascii_lowercase, k=8))
    return f'{name}@{random.choice(domains)}'

def random_phone():
    return f'+7-{random.randint(100,999)}-{random.randint(100,999)}-{random.randint(1000,9999)}'

for _ in range(3):
    print(f'{random_email()} - {random_phone()}')
  

Py test python (написание тестов на python (pytest))

abcde123@test.com - +7-456-789-1234
fghij456@example.org - +7-321-654-9876
klmno789@demo.net - +7-111-222-3333
  

Test data python (создание тестовых данных в python)

Проблемы:

  • Данные не выглядят реалистично (нет имен, адресов).
  • Сложно обеспечить уникальность и связанность.
  • При увеличении объема код становится громоздким.

Рекомендуется только для очень простых случаев или когда нельзя устанавливать сторонние пакеты.

Как генерировать объекты с бизнес-логикой с помощью factory_boy?

Библиотека factory_boy (установка: pip install factory_boy) позволяет описывать фабрики для создания объектов Python или ORM-моделей, автоматически связывая зависимости.


from factory import Factory, Faker, SubFactory
from dataclasses import dataclass

@dataclass
class User:
    name: str
    email: str

@dataclass
class Order:
    user: User
    total: float

class UserFactory(Factory):
    class Meta:
        model = User
    name = Faker('name')
    email = Faker('email')

class OrderFactory(Factory):
    class Meta:
        model = Order
    user = SubFactory(UserFactory)
    total = Faker('pyfloat', min_value=10, max_value=500, right_digits=2)

user = UserFactory()
order = OrderFactory()
print(f'{user.name} - {user.email}')
print(f'Order: {order.user.name} - {order.total} руб')
  
Иванова Мария - maria@example.com
Order: Иванова Мария - 125.67 руб
  

Типичные ошибки:

  • Неправильная конфигурация Meta.model - фабрика не создаст объект.
  • Циклические зависимости - используйте SelfAttribute или RelatedFactory с постгенерацией.
  • Импорт Faker из factory - работает только если Faker установлен.

Как альтернатива Faker: библиотека Mimesis?

Mimesis (установка: pip install mimesis) - ещё одна библиотека для генерации фейковых данных, сфокусированная на производительности и большом количестве провайдеров.


from mimesis import Person, Address, Datetime

person = Person('ru')
address = Address('ru')
dt = Datetime()

for _ in range(2):
    print(f'{person.full_name()}, {person.email()}, {address.city()}, {dt.date()}')
  
Смирнов Алексей, smirnov@mail.com, Москва, 2023-05-12
Кузнецов Иван, ivan@yandex.ru, Санкт-Петербург, 2023-05-12
  

Проблемы:

  • Меньшее комьюнити и документация по сравнению с Faker.
  • Некоторые провайдеры менее гибкие (например, нет unique напрямую).
  • При смене локали требуется пересоздавать объекты провайдеров.

Как вручную подготовить тестовые данные для малых объемов?

Для 1–10 записей можно просто написать данные в коде с помощью словарей или списков. Это не требует установки библиотек и полностью контролируется.


users = [
    {'id': 1, 'name': 'Alice', 'email': 'alice@test.com'},
    {'id': 2, 'name': 'Bob', 'email': 'bob@test.com'},
]
print(users)
  
[{'id': 1, 'name': 'Alice', 'email': 'alice@test.com'}, {'id': 2, 'name': 'Bob', 'email': 'bob@test.com'}]
  

Недостатки:

  • Не подходит для больших объемов (сотни и тысячи записей).
  • Ручное изменение данных при смене требований трудозатратно.
  • Отсутствует случайность - данные предсказуемы.

Расширенные примеры генерации тестовых данных

Генерация JSON для тестирования REST API со связанными сущностями

Создаётся структура: пользователи, заказы, товары. Используется Faker с уникальными идентификаторами и внешними ссылками.

Пример

from faker import Faker
import json

fake = Faker('ru_RU')

# Генерация пользователей
users = []
for user_id in range(1, 5):
    users.append({
        'id': user_id,
        'name': fake.name(),
        'email': fake.unique.email()
    })

# Генерация товаров (категории и цены)
categories = ['Electronics', 'Books', 'Clothing']
products = [{
    'id': i,
    'name': fake.catch_phrase(),
    'category': fake.random_element(categories),
    'price': round(fake.random_number(digits=4) / 100, 2)
} for i in range(1, 10)]

# Генерация заказов
orders = []
for order_id in range(1, 15):
    user = fake.random_element(users)
    product = fake.random_element(products)
    orders.append({
        'id': order_id,
        'user_id': user['id'],
        'product_id': product['id'],
        'quantity': fake.random_int(1, 5),
        'order_date': fake.date_time_this_year().isoformat()
    })

# Сохранение в файл
data = {'users': users, 'products': products, 'orders': orders}
with open('test_data.json', 'w', encoding='utf-8') as f:
    json.dump(data, f, ensure_ascii=False, indent=2)
print('JSON created with', len(users), 'users,', len(products), 'products,', len(orders), 'orders')
  
JSON created with 4 users, 9 products, 14 orders
  

Генерация данных для базы данных с внешними ключами

Используется Faker с явным заданием ID и ссылок. Пример для SQLite (но можно для любой БД).

Пример

import sqlite3
from faker import Faker

fake = Faker()
conn = sqlite3.connect(':memory:')
c = conn.cursor()
c.execute('CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)')
c.execute('CREATE TABLE orders (id INTEGER PRIMARY KEY, user_id INTEGER, total REAL)')

# Вставка пользователей
user_ids = []
for _ in range(100):
    name = fake.name()
    email = fake.unique.email()
    c.execute('INSERT INTO users (name, email) VALUES (?, ?)', (name, email))
    user_ids.append(c.lastrowid)

# Вставка заказов, привязанных к случайным пользователям
for _ in range(500):
    user_id = fake.random_element(user_ids)
    total = round(fake.random_number(digits=4) / 100, 2)
    c.execute('INSERT INTO orders (user_id, total) VALUES (?, ?)', (user_id, total))

conn.commit()
c.execute('SELECT COUNT(*) FROM orders')
print('Orders count:', c.fetchone()[0])
c.execute('SELECT COUNT(DISTINCT user_id) FROM orders')
print('Distinct users in orders:', c.fetchone()[0])
conn.close()
  
Orders count: 500
Distinct users in orders: 100
  

Проблемы при работе с БД:

  • Нарушение внешних ключей, если ссылаться на несуществующий ID. Решение - заранее сгенерировать все ID и выбирать из них.
  • Необходимость поддержания уникальности email. Используйте unique.email() или добавить суффикс.

Создание пользовательского провайдера для Faker

Расширение Faker для генерации доменных данных, например, номера СНИЛС или внутреннего кода продукта.

Пример

from faker import Faker
from faker.providers import BaseProvider

class CustomProvider(BaseProvider):
    def snils(self):
        # генерация номера СНИЛС (9 цифр + контрольное число)
        body = [self.random_int(0, 9) for _ in range(9)]
        # упрощённый расчёт контрольного числа
        checksum = sum((9 - i) * body[i] for i in range(9)) % 101
        if checksum > 99:
            checksum = 0
        return ''.join(map(str, body)) + str(checksum).zfill(2)

fake = Faker()
fake.add_provider(CustomProvider)

for _ in range(3):
    print(fake.snils())
  
12345678900
98765432144
11223344568
  

Возможные ошибки:

  • Неверная реализация алгоритма - данные не будут соответствовать формату.
  • Конфликт имён с существующими провайдерами Faker.

Генерация временных рядов с датами и значениями

Полезно для тестирования аналитических приложений. Используется Faker и dateutil.

Пример

from faker import Faker
from datetime import datetime, timedelta
import random

fake = Faker()
start_date = datetime(2023, 1, 1)
end_date = datetime(2023, 12, 31)
data = []
for _ in range(100):
    sensor_id = fake.random_int(1, 10)
    ts = fake.date_time_between(start_date=start_date, end_date=end_date)
    value = round(random.uniform(10, 30), 2)
    data.append({'sensor_id': sensor_id, 'timestamp': ts.isoformat(), 'value': value})

print(data[0])
print('Generated', len(data), 'records')
  
{'sensor_id': 5, 'timestamp': '2023-06-15T14:23:45', 'value': 22.41}
Generated 100 records
  

Проблемы:

  • Даты могут располагаться в хаотичном порядке - для последовательных рядов используйте date_time_ad() с шагом.
  • Большие объёмы - рассмотрите генерацию с помощью itertools.accumulate.

Генерация большого объёма данных (1 млн записей) с прогресс-баром

Используется Faker + tqdm для отслеживания прогресса. Важно оптимизировать - генерировать данные пакетами и не сохранять все в список.

Пример

from faker import Faker
from tqdm import tqdm
import json

fake = Faker()
num_records = 1_000_000
generator = ({
    'id': i,
    'name': fake.name(),
    'email': fake.email()
} for i in range(num_records))

# Запись напрямую в файл частями
with open('big_data.jsonl', 'w', encoding='utf-8') as f:
    with tqdm(total=num_records, desc='Generating') as pbar:
        for record in generator:
            f.write(json.dumps(record, ensure_ascii=False) + '\n')
            pbar.update(1)

print('Done')
  
Generating: 100%|██████████| 1000000/1000000 [00:45<00:00, 22000.00it/s]
Done
  

Типичные ошибки при больших объёмах:

  • Хранение всего списка в памяти - используйте генераторы и потоковую запись.
  • Низкая скорость - используйте Faker.seed() для воспроизводимости или мультипроцессинг.
  • Ошибки уникальности - для 1 млн email используйте уникальный генератор с большим пулом доменов.

Создание тестовых данных в Python - comments

En
Test data python (python)