Search
Write a publication
Pull to refresh
45.45
Программный Продукт
Создаем решения для государства и бизнеса

Методология генерации случайных строк посредством регулярных выражений

Reading time5 min
Views3.5K

Привет, Хабр!

Если ваш проект вырос, в нем бэкенд с фронтендом, различные точки входа API, интеграции с внешними системами, сложные алгоритмы, проверки введенных данных пользователем на валидность, диаграммы бизнес-процессов имеют тысячи ветвей, то скорее всего регрессионное тестирование занимает кучу времени, и проводить его вручную уже невыгодно. Проще эту работу поручить машине и тестировать продукт автоматически.  Первый вопрос, который возникает — «Как генерировать данные?», а конкретнее, как генерировать то, что может ввести пользователь. Этот вопрос мы и разберем в данной статье.

Обычно введенные строки сравнивают с некими шаблонами, среди которых наиболее распространенный– RegExr (регулярное выражение). Самый логичный способ — тестировать шаблон шаблоном.

Что такое и из чего состоит RegExr:

RegExr — шаблон, в котором представлена совокупность правил для конкретных позиций в строке.

Для единичных символов понятно, на этой позиции может быть только он. А в квадратных скобках указаны возможные варианты символов, например [1-9#] на этой позиции возможны только символы — 123456789#, а для правила [^@\.]  возможны любые символы кроме @ и . (напомню, что символ ^ после открывающей скобки означает «кроме»)

Квантификатор даёт нам информацию о том, на сколько позиций распространяется символ или символьная группа перед ним.

Квантификатор

Использование

{n}

Ровно n повторений

{m,n}

От m до n повторений

{m,}

Не менее m повторений

{,n}

Не более n повторений

?

Ноль или одно повторение

То же, что и {0,1}

*

Ноль или более повторений

То же, что и {0,}

+

Одно или более повторений

То же, что и {1,}

 

Все как в алгебре, скобки группируют и в основном работают с квантификаторами. В примере выражение в скобках может повторяться один и более раз:

Логика “или” позволяет сделать наше выражение более эластичным. В примере строка может состоять либо из 6 цифр, либо из 10. Выражений разделенных элементом | может быть  сколько угодно, но на этом месте может быть только одно из них.

Проблематика:

Например, поле email не принимает случайный набор символов, естественно там присутствует проверка через регулярное выражение, и в самом простом виде это [^@]+@([^@\.]+\.)+[^@\.]+. Соответственно, нам нужно либо захардкодить значение на каждое поле, либо при каждом тесте генерировать строку, которая подойдет под это выражение.
Чем обернется хардкод: 

1. Вы не сможете поддерживать свои тесты, так как ваш продукт меняется, и искать часами, где именно прошлый разработчик указал данные для этого поля долго и невыгодно.

2. Возникает риск ошибки, ведь по основному принципу тестирования мы тестируем черный ящик и не знаем какое там регулярное выражение, так как программист мог спокойно указать [^@]+@[^@\.]+\.[^@\.]+, и misha@mail.ru пройдет, а diana@inform.bigdata.ru нет.

3. Банально под ваши тесты могут подогнать регулярное выражение :)

Соответственно, правильно будет каждый раз генерировать новую случайную строку. Рекомендую писать свое регулярное выражение для генерации, основываясь на ТЗ, а не таскать их из кода.  Для того, чтобы сгенерировать случайную строку, нужно решить две основные проблемы:

1. Какие рамки поставить для квантификаторов +, {m,}, *. Ведь бесконечное количество символов мы сгенерировать не можем, а строка из тысячи символов только нагрузит интерфейс и особо никак не повлияет на тестирование. Тут нужно найти баланс и случайно не написать стресс-тест.

2. Откуда брать символы для генерации такого выражения — [^@\.]? Из таблицы ASCI? Но там довольно много специальных символов, и в итоге мы получим непонятную кашу.

Ответив на эти вопросы, мы сможем реализовать генерацию. Первый вопрос решается выбором верхней планки длины строки или квантификатора, например 50 символов. А второй — собственной библиотекой символов для проекта.

Задача:

Для генерации строки из выражения нужно разложить его на такие части, которые будет принимать конечный  автомат. То есть нужно привести к такому виду, что некая функция будет принимать его части на вход (множество символов B), выбирать такой символ a, который принадлежит этому множеству и выдавать этот символ.

Метод генерации строки из регулярного выражения

Приведу свою блок-схему алгоритма генерации включающую в себя 5 основных этапов:

1 Этап — декомпозиция основного выражения на подгруппы:

2 Этап — выбор между возможными вариантами:

Для оптимизации времени выполнения алгоритма, этот этап выполняется сразу после декомпозиции и позволяет не тратить времени на генерацию ненужных символов.

3 Этап — обработка символьных групп:

На этапе происходит замена шаблонов и формирование множеств для конечных автоматов.

4 Этап — обработка квантификаторов:

На этом этапе нам требуется выбрать конкретные значения для квантификаторов. Тут мы сталкиваемся с проблемой описанной ранее, квантификаторы +, *, {n,} представляют диапазоны чисел от n до бесконечности, с такими диапазонами мы работать не можем, поэтому требуется ограничение, например от n до n + 50. Потом для диапазонов нам нужно выбрать конкретное значение, оно и будет означать количество запусков конечных автоматов.  Далее мы «разворачиваем» выражения в круглых скобках в зависимости от значения их квантификатора.

Отмечу, что мы должны рекурсивно запускать алгоритм для каждой группы столько раз, сколько указано в её квантификаторе.

Приведу пример работы квантификатора, который должен запускать именно то количество конечных автоматов, которое указано для него, а не «умножать» результат работы.

5 Этап — Запуск конечных автоматов.

После всех этих этапов мы получаем общность конечных автоматов, которые и требуется запустить:

Зачем изобретать велосипед?

Увы, но нет универсальных решений, и под свои задачи нужно либо модифицировать, либо писать что-то самостоятельно. Например, на нашем проекте для автоматического тестирования API был выбран язык Python. Он простой, удобный, и обучение специалиста, который сможет поддерживать фреймворк — дело буквально месяца-двух.  У нас несколько требований к библиотеке генерации случайных строк:

  1. Быстрая;

  2. Удобная;

  3. Должна поддерживать основную лексику регулярных выражений;

  4. В начале и конце сгенерированной строки не должно быть пробелов.

В своих поисках мы нашли 4 библиотеки: xeger, strgen, exrex, rstr.

Strgen – самая быстрая, практически идеальна, но не поддерживает многие квантификаторы.

Xeger — реализована не самая удобная работа с библиотеками символов и первоначальными настройками.

Rstr — Не самая стабильная библиотека, в некоторых моментах работает в 5 раз медленнее других.

Exrex — генерирует 1000 случайных строк в среднем за 2 секунды, не критично, но можно лучше.

Хотелось бы получить универсальную, быструю библиотеку, подходящую под наши требования. Вот так и появилась на свет библиотека re_generate (pypi.org/project/re-generate). Получилось даже лучше, чем мы думали, уже до оптимизации алгоритм выдает хорошие показатели в сравнительных бенчмарках:

Итог:

Если вы не нашли уже готового решения для вашего проекта, рекомендуем реализовать этот алгоритм, таким образом вы получите практику и прекрасный инструмент для работы. Забирайте в свои проекты, пользуйтесь, реализуйте. Спасибо за внимание!

 

Tags:
Hubs:
Total votes 3: ↑3 and ↓0+3
Comments8

Articles

Information

Website
ppr.ru
Registered
Founded
2002
Employees
501–1,000 employees
Location
Россия