
Каждый день тысячи инженеров изо всех сил стараются обеспечить качество и достоверность данных: сохранить каждую транзакцию целой и невредимой. Но зачастую нужно обратное — нарочно испортить данные или придумать их с нуля. Оказывается, это тоже непросто.
Меня зовут Максим Грамин (@mgramin), и в этой статье я расскажу, что такое ненастоящие (фейковые, синтетические, тестовые — как угодно) данные, для чего они могут понадобиться, как их генерировать и использовать. Статья написана по мотивам доклада на конференции PGConf.Russia.
Случай из жизни
Представьте, что вы разрабатываете новую информационную систему. Чтобы протестировать базовую функциональность, например, регистрацию и авторизацию, вам нужны тестовые данные: логины, ФИО, адреса электронной почты, номера телефонов и так далее. При этом система будет проверять их валидность и уникальность: свободен ли логин, корректна ли почта, соответствует ли адрес формату.
Использовать для этих целей реальные данные — плохая идея. На то есть несколько веских причин:
Законность. Во многих странах это запрещено или строго ограничено законодательством о защите персональных данных (GDPR в Европе или 152-ФЗ в России).
Безопасность. Тестовые среды обычно защищены слабее, чем продакшен-среды. Использование реальных данных несёт огромный риск утечки, ведь чувствительная информация может попасть в руки мошенникам или оказаться в незащищённом окружении.
Масштабируемость. Реальных данных может попросту не хватить. Например, если нужно создать не одну учётную запись, а десятки и тысячи с разными ролями и наборами привилегий для проверки сложных сценариев.
Самое простое и очевидное решение — использовать экземплификантов (Иван Иванов, Вася Пупкин, John Doe и так далее), но их запас и ваше терпение могут быстро закончиться, и придётся вбивать бессмысленные наборы символов. А если нужно протестировать нагрузку на систему с сотней или тысячей пользователей, то ваш тестовый стенд превратится в свалку бессистемных и невалидных данных, которые лишь отдалённо напоминают реальные. Уверен, многим знакома эта удручающая картина:

Помимо неэстетичного вида, у таких данных возникают практические проблемы — чем больше данных, тем они сложнее:
Валидация. Приложение и БД почти всегда проверяют длину логина и комментария, формат email и телефона. Случайные данные таких проверок обычно не пройдут.
Уникальность. Логины, имейлы, внутренние идентификаторы должны быть уникальными в рамках всей таблицы или определённой группы (например, отдела или компании).
Бизнес-логика. Данные должны отражать реальные бизнес-сценарии. Например, у пользователя из отдела кадров должна быть роль «HR», а заказ не может быть доставлен раньше, чем создан.
К счастью, существует множество способов генерации качественных тестовых данных, которые не только выглядят как настоящие, но и соблюдают все правила вашей системы. В идеале нужно стремиться к тому, чтобы ваши данные выглядели примерно так:

В итоге вы получите тот же самый набор полей (ФИО, должность, адрес), выглядящий на порядок солиднее и решающий все проблемы, о которых говорили выше:
Безопасность. Данные полностью синтетические — все имена, адреса и должности вымышлены, а значит, не несут рисков даже при утечке.
Правдоподобность. Информация выглядит как настоящая, что критически важно для тестирования UI/UX и логики приложения.
Валидность. Данные готовы к любым проверкам: от формата имела до сложных скриптов бизнес-логики.
О том, какими способами можно добиться такого результата и какие подводные камни ждут на этом пути, разберёмся прямо сейчас.
Для чего нужны «ненастоящие» данные
Сфера применения синтетических данных оказывается намного шире, чем кажется на первый взгляд. Вот лишь основные сценарии:
Функциональное тестирование. Можно нагенерировать огромное количество разнообразных кейсов — от корректных до самых экзотических — и проверить, как система отреагирует на каждый. Сработают ли все триггеры? Не рухнет ли всё при попытке сохранить неверный формат? Здесь фейковые данные незаменимы.
Нагрузочное тестирование. Что будет, если пользователей станет в 100 раз больше? Чтобы это выяснить, нужны данные, которые имитируют этот наплыв. Генерация позволяет создать датасет, по объёму превосходящий продакшен, и найти узкие места до того, как это сделают реальные пользователи.
Демо и пилоты. Показать работающий прототип с реальными данными клиента — это моветон и часто нарушение NDA. А вот с качественными фейковыми данными — пожалуйста. Красиво, безопасно и не скомпрометирует ни один реальный аккаунт.
Такие данные можно без опаски передавать подрядчикам, показывать на конференциях или партнёрам — утечка не нанесёт никакого ущерба. А ещё они отлично подходят для скриншотов для документации или статей — как есть, без дополнительных манипуляций с маскировкой.
Как получить «ненастоящие» данные: четыре подхода
В зависимости от исходной задачи и самих данных тестовые данные можно получить одним из четырёх способов:
Маскирование. Идеально, когда нужно создать тестовый стенд на основе реальной продакшен-базы. Персональные данные обезличиваются — в них заменяются или шифруются конкретные значения. Ключевое преимущество: сохраняется структура и объём данных, их статистические свойства и, что критически важно, реляционная целостность (связи между таблицами). На выходе — полная копия продакшена, но без риска утечки.
Генерация с нуля (from scratch). Подходит для развёртывания среды «на пустом месте» — с чистым дампом схемы БД. Данные создаются искусственно, на основе описания форматов, правил валидации и требуемого объёма. Отличный вариант для создания предсказуемых датасетов под конкретные сценарии тестирования или инициализации новых проектов.
Экстраполяция. Поможет в тех случаях, когда у вас есть исторические данные и нужно спрогнозировать нагрузку на перспективу. Этот метод позволяет «размножить» и дополнить существующие данные, чтобы смоделировать, например, поведение системы при двукратном росте пользователей или через год активной эксплуатации. Позволяет находить узкие места «на вырост».
Комбинированный подход. Самый распространённый и практичный сценарий. В реальном проекте почти всегда приходится использовать все методы сразу: маскирование для таблиц с персональными данными пользователей и сотрудников, экстраполяцию для таблиц транзакций и заказов, чтобы нагнать объём и смоделировать будущую нагрузку, а генерацию с нуля для новых фич, под которые ещё не созданы таблицы на продакшене.
Инструментарий: от скриптов до data-фабрик
Для решения задач маскирования и генерации существует множество инструментов, которые условно можно разделить на три категории по нарастанию сложности и охвата.
DIY-скрипты. Можно написать собственные скрипты на SQL или любом другом языке с использованием библиотек, например, классический Python Faker или его специализированных обёрток для PostgreSQL, вроде pg_faker. Главное преимущество этого метода — полный контроль над процессом и простота начала работы. Однако есть и существенный минус: поддержка таких скриптов становится очень трудоёмкой при частых изменениях схемы данных. Этот способ идеально подходит для разовых задач или работы со статичными, редко меняющимися схемами.
Опенсорсные решения PostgreSQL Anonymizer, GreenMask, которые сканируют базу, используют декларативные конфиги (YAML, JSON) для описания правил маскирования и генерации и применяют их ко всей БД. Их ключевые плюсы — это автоматизация процесса и способность поддерживать целостность данных благодаря мощным встроенным стратегиям. С другой стороны, они требуют времени на изучение и первоначальную настройку. Эти инструменты отлично подходят для регулярного создания тестовых копий продакшн-баз с полным сохранением реляционной целостности.
Test Data Management (TDM), например, Tonic, Gretel и многие другие. Это уже не просто утилиты, а целые фабрики данных. Они работают и с БД, и с другими источниками, могут создавать и разворачивать по запросу целые тестовые среды в облаке. Их главные преимущества — максимальная автоматизация, масштабируемость и работа с комплексными средами. Недостатки — высокая стоимость и сложность внедрения. Эти платформы используются в крупных корпоративных средах, где нужно постоянно управлять жизненным циклом тестовых данных.
Несмотря на разнообразие выбора, под капотом большинства этих инструментов работают общие, фундаментальные паттерны — так называемые fake data patterns. Рассмотрим их подробнее.
Паттерны маскировки
Статическое маскирование — один из самых простых и надёжных подходов. Его суть заключается в замене чувствительных данных на фиктивные значения, которые могут частично или полностью сохранять формат оригинальных данных. Например, можно замаскировать имейл, сохранив его структуру (часть до «@» и домен), но изменив сами символы.
Основное преимущество статического маскирования — простота реализации: даже с помощью стандартных SQL-функций можно прямо на коленке сделать что-то вменяемое. Однако у метода есть важные ограничения: такие данные нельзя использовать в качестве первичных или внешних ключей, так как это нарушит целостность связей. Кроме того, маскированные значения могут не проходить бизнес-валидацию, если приложение проверяет их содержание на соответствие реальным шаблонам.
Хеширование — ещё один популярный метод, который позволяет обезличить данные, сохраняя их уникальность. Для этого используются различные хеш-функции (как стандартные, так и нестандартные). Некоторые инструменты могут предлагать более продвинутые варианты — например, хеширование с сохранением формата. Это позволяет замаскировать имейл так, чтобы он оставался валидным с точки зрения структуры, но при этом не раскрывал настоящие данные. Важное преимущество хеширования — детерминированность: одинаковые исходные значения дают одинаковый хеш, что позволяет сохранять связи между таблицами. Это особенно полезно для тестирования сложных систем со взаимосвязанными данными.
Есть и другие важные паттерны маскирования данных:
Добавление шума (Noising) в исходные значения. Это подходит для числовых данных, где нужно сохранить статистические характеристики, но сделать конкретные значения неузнаваемыми. Например, к зарплате сотрудника можно добавить случайное отклонение в пределах ±10%.
Генерализация (Generalization) заменяет точные значения на более общие диапазоны или категории. Вместо конкретного возраста 28 лет можно указать диапазон 20–40 лет, а вместо точного местоположения — город или район. Этот подход сохраняет аналитическую ценность данных, но скрывает детали.
Агрегация (Aggregation) подменяет исходные данные обобщёнными статистическими показателями. Например, вместо отображения индивидуальных зарплат можно показать среднее значение по отделу или медиану по компании. Такой подход часто используется в отчётности и аналитике.
Маскирование на основе правил (Rule-based masking) позволяет применять сложную бизнес-логику для маскирования. Например, можно скрыть названия фильмов с возрастным ограничением 18+, заменить номера кредитных карт по определённому шаблону или по-разному маскировать данные в зависимости от роли пользователя, который к ним обращается.
Перемешивание (Shuffling) меняет местами значения одной колонки, сохраняя состав данных, но нарушая их соответствие исходным записям.
Маскирование структурированных данных — специальные методы для работы со сложными форматами данных. Для JSON и XML это может означать маскирование значений по ключам, обработку вложенных структур или даже изменение структуры документа. Для бинарных данных применяются специальные алгоритмы, сохраняющие формат файлов.
Рандомизированное маскирование заменяет исходные значения случайными данными, соответствующими определённому формату. Например, можно сгенерировать случайный email, номер телефона или идентификатор, который будет сохранять все характеристики исходного значения, но не будет содержать реальной информации.
Каждый из этих подходов имеет свои преимущества и ограничения, и часто наилучшие результаты достигаются при комбинировании нескольких методов для разных типов данных и сценариев использования.
Паттерны генерации
Генерация строк
В первую очередь для тестирования или запуска приложения нам необходимо заполнить пустые таблицы данными — будь то несколько строк или миллионы записей. Специализированные инструменты решают эту задачу элементарно: достаточно указать желаемое количество строк (в абсолютных или относительных величинах) в графическом интерфейсе или конфигурационном файле, и данные появятся как по волшебству.
Если выбирать из стандартных средств, на помощь придёт наш любимый SQL. Современные стандарты SQL (начиная с версии 1999 года) позволяют генерировать последовательности строк с помощью рекурсивных запросов. Это мощный, хотя и не всегда очевидный в реализации метод:
with recursive tmp (r) as (
select 0
union all
select r+1
from tmp
where r < 100500)
select r from tmp
Для пользователей PostgreSQL генерацию упрощает встроенная функция generate_series
, которая позволяет создавать числовые, временные и даже текстовые последовательности всего парой строк кода. Это идеальная точка входа для быстрой генерации тестовых данных на уровне базы данных:
select generate_series
from generate_series(1, 100500)
На тему generate_series
рекомендую просто шикарную серию статей от Timescale.
Генерация значений
Когда каркас в виде строк создан, нужно наполнить их данными. На старте и для простых задач вполне достаточно встроенных возможностей самой СУБД. Такой подход отлично работает для быстрого прототипирования, проверки базовой функциональности или построения отчётов, когда реалистичность данных не критична. Вот как это выглядит в PostgreSQL с помощью функции generate_series()
и встроенных генераторов случайных значений:
select
md5(random()::text) as name,
floor(random() * 99)::int as years_of_experience,
md5(random()::text) || '@gmail.com' as email,
now() - (random() * (interval '90 days')) as order_date,
case when random() > 0.5 then true else false end as is_student
from generate_series(1, 1000)
В реальных проектах требуются куда более правдоподобные данные. К счастью, большинство современных инструментов генерации умеют создавать реалистичные примитивы: имена, фамилии, адреса, имейлы, номера документов и телефонов с различной степенью кастомизации и локализации. Например, многие инструменты позволяют генерировать:
демографические данные (ФИО) с учётом региональных особенностей (на кириллице для России, на латинице для европейских стран);
адреса, соответствующие реальным почтовым форматам разных стран;
валидные номера документов (паспортов, водительских прав) с контрольными суммами, а также настраивать форматы телефонных номеров в соответствии с масками разных операторов;
электронные адреса с привязкой к доменам.
Это позволяет создавать данные, которые не только выглядят достоверно, но и проходят формальные проверки на валидность, что критически важно для тестирования бизнес-логики приложений.
Обратите внимание и на другие важные паттерны генерации данных:
Генерация связанных значений — создание данных для разных полей и таблиц, логически связанных между собой. Например, генерация email на основе имени и фамилии пользователя или сохранение соответствия между кодами регионов в разных таблицах. Такой подход обеспечивает целостность данных и их правдоподобность.
Генерация на основе родительских таблиц — учёт внешних ключей и связей между таблицами. При генерации данные для дочерней таблицы должны соответствовать записям в родительской таблице.
-
Генерация для рекурсивно связанных таблиц — таблиц с циклическими ссылками (например, таблица сотрудников со ссылкой на руководителя в той же таблице) предусматривает:
анализ бизнес-логики рекурсивной связи;
определение допустимой глубины вложенности;
исключение циклических ссылок в данных;
использование итеративных или рекурсивных алгоритмов генерации.
Каждый из этих паттернов требует глубокого понимания структуры базы данных и бизнес-логики приложения. Реализация может включать как использование специализированных инструментов, так и разработку кастомных решений на основе SQL-запросов или скриптов.
С чего начать?
Детально изучите схему своей БД — без этого не будет качественного результата. Не забывайте о триггерах и хранимых процедурах: они могут незаметно влиять на данные в процессе их генерации или маскирования.
Выберите подходящий инструмент под ваши задачи и стек технологий. Иногда приходится искать обходные пути, будьте к этому готовы. Убедитесь, что ваш инструмент или скрипт позволяют выборочно обрабатывать отдельные таблицы или их части.
Создайте тестовый полигон — сгенерируйте данные, примените базовое маскирование и проверьте результат вместе с коллегами.