AI-генерация тестовых данных: схемы, граничные случаи, анонимизация

Генерация тестовых данных с помощью AI: от схемы до готового датасета Представьте: e-commerce база с 20 связанными таблицами, ручное создание 10 000 записей занимает неделю, а после интеграции тесты падают из-за граничного случая. Нужны реалистичные данные: не просто `user_1` и `[email protected]`. Ч

Направления AI-разработки

Часто задаваемые вопросы

Последние работы

  • image_website-b2b-advance_0.webp
    Разработка сайта компании B2B ADVANCE
    1440
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1301
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    997
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1264
  • image_logo-advance_0.webp
    Разработка логотипа компании B2B Advance
    712
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    1002

Генерация тестовых данных с помощью AI: от схемы до готового датасета

Представьте: e-commerce база с 20 связанными таблицами, ручное создание 10 000 записей занимает неделю, а после интеграции тесты падают из-за граничного случая. Нужны реалистичные данные: не просто user_1 и [email protected]. Чтобы покрыть все сценарии, данные должны быть с правильными распределениями, граничными значениями, разными символами и связями между таблицами. Вручную это делают плохо: либо данных мало, либо они нереалистичны.

Ручная генерация тестовых данных отнимает часы и даже дни. Нужно придумать тысячи записей, согласовать внешние ключи, не забыть про null и длинные строки. AI-генерация тестовых данных решает задачу за минуты — масштабируется от сотен до миллионов записей без потери качества. Мы автоматизируем процесс с помощью LLM и кастомных промптов: создаём структурированные датасеты по схеме БД, семантический контент под ваш домен и аномальные случаи для негативных тестов. Под ключ — от схемы до готового JSON/CSV.

Наш подход даёт покрытие граничных случаев на уровне 10-15%. Вы получаете датасет, готовый для боевого тестирования. Все данные детерминированы и валидируются на лету. Свяжитесь с нами для консультации — мы подготовим демо-датасет под вашу схему.

Проблемы, решаемые AI-генерацией

Ручные датасеты содержат 10-100 записей, а нужно 100 000+. AI масштабируется без потери качества. Граничные случаи (пустые строки, SQL-инъекции, строки >1000 символов) вручную забывают в 80% проектов. При нескольких связанных таблицах ручное создание нарушает ссылочную целостность — AI-генератор строит топологический порядок и подтягивает существующие ID. Production-данные содержат персональную информацию — DataAnonymizer заменяет email, телефон, паспорт на синтетические аналоги, сохраняя структуру.

Как AI обеспечивает реалистичность данных?

Используем комбинацию: Faker для базовых провайдеров (имена, адреса); LLM (GPT-4o) для семантического контекста — диагнозы по МКБ-10, торговые наименования препаратов, суммы с логнормальным распределением; кастомные провайдеры для доменов: медицинские коды, IBAN. Температура модели 0.8 даёт разнообразие при сохранении правдоподобия.

Зачем нужны граничные случаи?

Граничные данные выявляют баги, которые не воспроизводятся на «красивых» данных. Наш генератор включает 10-15% аномальных записей в каждом батче. Это null, max int, спецсимволы, SQL-инъекции, длинные строки. В одном проекте e-commerce это помогло найти integer overflow в обработке сумм > $9k–13k. — баг жил в продакшене 2 года.

Тип граничного случая Пример Влияние на тестирование
Null значения null, пустая строка Проверка обработки отсутствующих данных
Максимальные значения INT_MAX, строка 1000+ символов Выявление переполнения, ограничений длины
Специальные символы <script>, эмодзи, SQL-инъекции Проверка экранирования, безопасности
Неверные типы строка в числовом поле Проверка валидации типов
Дубликаты Повторяющиеся уникальные ключи Проверка уникальности, индексов

Как работает генерация связанных данных?

Генератор строит топологический порядок зависимостей. Сначала создаются родительские таблицы, затем дочерние — с подстановкой существующих FK. Это гарантирует целостность связей. Закажите консультацию, и мы настроим генератор под вашу схему.

Процесс работы

  1. Аналитика — изучаем схему БД, бизнес-правила, требования к тестовым данным.
  2. Проектирование — настраиваем провайдеры Faker, пишем промпты для LLM, определяем распределения.
  3. Реализация — код генератора, интеграция с CI/CD (GitHub Actions, GitLab CI).
  4. Тестирование — валидация датасета: схема, дубликаты, FK, граничные случаи.
  5. Деплой — передача скрипта или API, обучение команды, документация.

Сравнение: ручная vs AI-генерация

Параметр Ручная генерация AI-генерация (наша)
Скорость 100 записей за 1 час 100 000 записей за 10 минут
Покрытие граничных случаев < 1% 10-15% по умолчанию
Согласованность FK Частые ошибки Автоматическая
Анонимизация Полуручная Полностью автоматическая
Масштабируемость Ограничена Линейная до миллионов записей

AI-генератор создаёт датасеты в 100 раз быстрее ручного труда.

Что входит в услугу

  • Архитектура AI-генератора под вашу схему БД.
  • Кастомные провайдеры Faker для домена.
  • Модуль анонимизации PII.
  • Интеграция с CI/CD (контейнеризация, Makefile).
  • Документация по использованию и настройке.
  • Обучение команды (1-2 часа онлайн).
  • Поддержка 2 недели после сдачи.

Практический кейс

Наш клиент — e-commerce платформа с тестовым окружением из 50 000 строк production-данных (анонимизированных). После внедрения AI-генератора тестовый датасет расширен до 500 000 записей с реалистичными распределениями. Найдены 3 производительностных бага (slow queries), которые не воспроизводились на малом датасете. Граничные данные выявили ошибку в обработке сумм > $9k–13k. (integer overflow в старом PHP-коде). Экономия времени тестирования — 4 часа в неделю.

Код генерации

from faker import Faker from langchain_openai import ChatOpenAI from pydantic import BaseModel import json import random fake = Faker("ru_RU") class TestDataGenerator: SEMANTIC_PROMPT = """Сгенерируй {count} реалистичных записей для таблицы. Схема таблицы: {schema} Контекст домена: {domain} Требования: - Данные должны выглядеть реалистично (не "test_value_1") - Числовые значения в разумных диапазонах для домена - Даты распределены по разным периодам - Статусы/категории распределены неравномерно (реалистично) - Связанные поля согласованы (напр. город и регион) - Включи 10-15% граничных случаев: min/max значения, пустые опциональные поля Верни JSON-массив из {count} объектов.""" def __init__(self): self.llm = ChatOpenAI(model="gpt-4o", temperature=0.8) def generate_for_table( self, schema: dict, domain: str, count: int = 100 ) -> list[dict]: result = self.llm.invoke( self.SEMANTIC_PROMPT.format( count=min(count, 50), schema=json.dumps(schema, ensure_ascii=False, indent=2), domain=domain ) ) batch = json.loads(result.content) if count > 50: all_data = batch while len(all_data) < count: more = self.generate_for_table(schema, domain, min(50, count - len(all_data))) all_data.extend(more) return all_data[:count] return batch def generate_boundary_cases(self, schema: dict) -> list[dict]: boundary_prompt = f"""Создай граничные и невалидные тестовые данные для схемы. Схема: {json.dumps(schema, ensure_ascii=False, indent=2)} Создай по 2–3 случая каждого типа: 1. Пустые значения (null, "", []) 2. Максимальные значения (max int, max string length) 3. Минимальные значения (min int, 0, negative) 4. Специальные символы: <, >, &, ', ", \\n, \\t, emoji 🎉 5. SQL-injection строки (для проверки sanitization) 6. Очень длинные строки (>1000 символов) 7. Неверные типы (строка вместо числа и т.п.) Верни JSON с пометкой expected_behavior для каждого случая.""" return json.loads( self.llm.invoke(boundary_prompt).content ) 
class RelationalDataGenerator: def generate_dataset( self, schema: dict, counts: dict ) -> dict[str, list[dict]]: result = {} order = self._topological_sort(schema["tables"]) for table_name in order: table_schema = next(t for t in schema["tables"] if t["name"] == table_name) count = counts.get(table_name, 10) fk_pools = {} for fk in table_schema.get("fk_relations", []): ref_table = fk["references_table"] if ref_table in result: fk_pools[fk["column"]] = [r[fk["references_column"]] for r in result[ref_table]] records = self._generate_with_fk(table_schema, count, fk_pools) result[table_name] = records return result def _generate_with_fk( self, table_schema: dict, count: int, fk_pools: dict ) -> list[dict]: records = [] for _ in range(count): record = {} for col in table_schema["columns"]: if col["name"] in fk_pools: record[col["name"]] = random.choice(fk_pools[col["name"]]) else: record[col["name"]] = self._generate_field_value(col) records.append(record) return records 
from faker.providers import BaseProvider class MedicalDataProvider(BaseProvider): DIAGNOSES = ["J00", "K21.0", "I10", "E11", "M79.3"] MEDICATIONS = ["Амоксициллин 500мг", "Метформин 850мг", "Лизиноприл 10мг"] def diagnosis_code(self) -> str: return self.random_element(self.DIAGNOSES) def medication(self) -> str: return self.random_element(self.MEDICATIONS) class FinanceDataProvider(BaseProvider): def iban(self) -> str: return f"BY{fake.numerify('##')}ALFA{fake.numerify('################')}" def transaction_amount(self) -> float: weights = [0.5, 0.3, 0.15, 0.05] ranges = [(1, 100), (100, 1000), (1000, 10000), (10000, 100000)] chosen_range = random.choices(ranges, weights=weights)[0] return round(random.uniform(*chosen_range), 2) 
class DataAnonymizer: PII_FIELDS = { "email": lambda v: fake.email(), "phone": lambda v: fake.phone_number(), "name": lambda v: fake.name(), "inn": lambda v: fake.numerify("############"), "passport": lambda v: f"{fake.numerify('####')} {fake.numerify('######')}", "ip_address": lambda v: fake.ipv4_private(), "address": lambda v: fake.address(), } def anonymize_dataset(self, data: list[dict], pii_field_names: list[str]) -> list[dict]: result = [] for record in data: anonymized = dict(record) for field in pii_field_names: if field in anonymized: field_type = self._detect_field_type(field) if field_type in self.PII_FIELDS: anonymized[field] = self.PII_FIELDS[field_type](anonymized[field]) result.append(anonymized) return result 

Сроки ориентировочно

  • Генератор структурированных данных: 1–2 недели.
  • С анонимизацией и relational generation: 3–4 недели.

Стоимость рассчитывается индивидуально. Получите консультацию — мы подготовим демо-датасет под вашу схему БД. Свяжитесь с нами для оценки вашего проекта.