/
Вопросы и ответы
/
Промт-инжиниринг
/

LLM для генерации тестовых данных

LLM для генерации тестовых данных

9 часов назад

Никита Вихров

Ответы

0

LLM для генерации тестовых данных

Хорошие тестовые данные — половина хорошего теста. Написать их вручную скучно и долго: нужны граничные случаи, реалистичные имена, правдоподобные сценарии. ИИ делает это быстро и разнообразно.


Базовая генерация по схеме

from anthropic import Anthropic
import json
import re

client = Anthropic()


def generate_test_data(schema: dict, count: int = 10, constraints: list[str] = None) -> list[dict]:
    constraints_text = "\n".join(f"- {c}" for c in (constraints or []))

    response = client.messages.create(
        model="claude-haiku-4-5",
        max_tokens=2048,
        system="Генерируешь тестовые данные. Отвечай только валидным JSON-массивом.",
        messages=[{
            "role": "user",
            "content": f"""Сгенерируй {count} объектов по этой схеме:
{json.dumps(schema, ensure_ascii=False, indent=2)}

{"Ограничения:" if constraints_text else ""}
{constraints_text}

Данные должны быть разнообразными и реалистичными.
Включи граничные случаи: пустые строки, максимальные значения, спецсимволы."""
        }]
    )

    text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
    return json.loads(text)


# Генерируем тестовых пользователей
user_schema = {
    "id": "integer (1-9999)",
    "name": "string (реальное русское имя)",
    "email": "string (валидный email)",
    "age": "integer (18-80)",
    "role": "enum: admin|manager|user",
    "balance": "float (0-100000, 2 знака после запятой)",
    "is_verified": "boolean",
    "created_at": "ISO 8601 datetime"
}

users = generate_test_data(
    user_schema,
    count=20,
    constraints=[
        "Один пользователь с balance=0",
        "Один пользователь с очень длинным именем (30+ символов)",
        "Два admin-пользователя",
        "Несколько пользователей с одинаковым именем но разным email",
    ]
)

for user in users[:3]:
    print(json.dumps(user, ensure_ascii=False))

Генерация сценариев для E2E-тестов

def generate_test_scenarios(feature: str, user_types: list[str]) -> list[dict]:
    response = client.messages.create(
        model="claude-sonnet-4-5",
        max_tokens=2048,
        messages=[{
            "role": "user",
            "content": f"""Сгенерируй тест-сценарии для фичи: {feature}

Типы пользователей: {', '.join(user_types)}

Для каждого сценария:
- given: начальное состояние
- when: действие пользователя
- then: ожидаемый результат
- type: happy_path | edge_case | error_case

Формат: JSON-массив объектов.
Обязательно включи: happy path, граничные случаи, ошибочные сценарии."""
        }]
    )

    text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
    return json.loads(text)


scenarios = generate_test_scenarios(
    feature="Оформление заказа с промокодом",
    user_types=["гость", "авторизованный пользователь", "премиум-пользователь"]
)

for s in scenarios:
    print(f"\n[{s['type']}] {s.get('title', '')}")
    print(f"Given: {s['given']}")
    print(f"When: {s['when']}")
    print(f"Then: {s['then']}")

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

def generate_load_test_data(
    endpoint: str,
    request_schema: dict,
    volume: int = 1000
) -> list[dict]:
    """Генерирует разнообразные данные для нагрузочного теста"""

    # Генерируем батчами по 100 — модель стабильнее на меньших объёмах
    all_data = []
    batch_size = 100

    for i in range(0, volume, batch_size):
        current_batch = min(batch_size, volume - i)

        response = client.messages.create(
            model="claude-haiku-4-5",
            max_tokens=4096,
            system="Генерируешь данные для нагрузочного тестирования. Только JSON-массив.",
            messages=[{
                "role": "user",
                "content": f"""Сгенерируй {current_batch} запросов к {endpoint}.
Схема запроса: {json.dumps(request_schema, ensure_ascii=False)}

Данные должны быть максимально разнообразными.
30% — типичные запросы, 50% — вариации, 20% — граничные случаи."""
            }]
        )

        text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
        batch_data = json.loads(text)
        all_data.extend(batch_data)
        print(f"Сгенерировано: {len(all_data)}/{volume}")

    return all_data


# Данные для нагрузочного теста поиска
search_data = generate_load_test_data(
    endpoint="POST /api/products/search",
    request_schema={
        "query": "строка поиска",
        "filters": {"category": "string|null", "min_price": "number|null", "max_price": "number|null"},
        "page": "integer (1-100)",
        "limit": "integer (1-50)"
    },
    volume=500
)

Генерация данных с соблюдением бизнес-правил

def generate_consistent_dataset(business_rules: list[str], entities: dict, count: int = 50) -> dict:
    """Генерирует взаимосвязанные данные с соблюдением бизнес-правил"""

    rules_text = "\n".join(f"- {rule}" for rule in business_rules)
    entities_text = json.dumps(entities, ensure_ascii=False, indent=2)

    response = client.messages.create(
        model="claude-opus-4-5",  # сложная задача — лучшая модель
        max_tokens=4096,
        messages=[{
            "role": "user",
            "content": f"""Сгенерируй тестовый датасет из {count} записей.

Сущности и их схемы:
{entities_text}

Бизнес-правила (обязательно соблюдать):
{rules_text}

Верни JSON объект где ключи — названия сущностей, значения — массивы записей."""
        }]
    )

    text = re.sub(r'```(?:json)?|```', '', response.content[0].text).strip()
    return json.loads(text)


dataset = generate_consistent_dataset(
    business_rules=[
        "У каждого заказа есть ровно один пользователь",
        "Сумма позиций заказа равна total_amount заказа",
        "Статус 'delivered' только если есть дата доставки",
        "Премиум-пользователи имеют скидку 15% на все заказы",
        "Нельзя заказать товар с количеством 0 на складе",
    ],
    entities={
        "users": {"id": "int", "name": "str", "is_premium": "bool"},
        "products": {"id": "int", "name": "str", "price": "float", "stock": "int"},
        "orders": {"id": "int", "user_id": "int", "items": "list", "total_amount": "float", "status": "str"},
    },
    count=30
)

На курсе «ИИ для разработчиков» на Хекслете разбирают как использовать ИИ на каждом этапе разработки — включая тестирование и работу с данными на реальном проекте.

9 часов назад

Никита Вихров

+7 800 100 22 47

бесплатно по РФ

+7 495 085 21 62

бесплатно по Москве

108813 г. Москва, вн.тер.г. поселение Московский,
г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3
ОГРН 1217300010476
ИНН 7325174845