Регулярные выражения в тестировании

Давно назрело желание поговорить о довольно редкой теме среди тестировщиков — регулярных выражениях. Не все тестировщики знают регулярные выражения. Часть умеет расшифровать и подобрать нужное регулярное выражение при помощи специальных онлайн-сервисов. Например, Rubular для руби. Иногда встречаются гуру, умеющие завязывать регулярные выражения морскими узлами любой сложности.

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

Справедливости ради, нужно признать, что регулярные выражения — не самая необходимая в повседневной работе вещь. При их изучении приходится придумывать невероятные варианты, где бы пригодилось знание конструкций вида "look ahead" или "if-then-else".

Всем расступиться. Я знаю регулярные выражения (с) автор неизвестен

Меня сподвигло к изучению регулярных выражений использование Cucumber на проекте. Это означает, что файл, представляющий собой по сути сплав варианта использования и тест-кейса на любом языке (стандарт де-факто - английский), распознается при помощи регулярных выражений. При нахождении совпадения для тестового шага вызывается соответствующий метод.

Так регулярные выражения пришли в мою жизнь и не ограничились тестовым фреймворком. Поэтому я начну с других сфер применения, приводя примеры на ruby.

1. Проверка на соответствие

Я ловлю себя на том, что вместо проверки if some_string == 'foo', я использую if some_string[/^foo$/i], если мне неважно, получу ли я "foo" или "Foo" или "fOo".

  • все, что не nil, считается в руби true. Поэтому если найдется совпадение - набор символов, образующих "foo" в любом регистре - результат выражения будет true.

2. Подстановка и замена

Пожалуй, без регулярок здесь и не обойтись.

3. Локаторы в некоторых реализациях PageObject

Например, поставлена задача описать локатор для поля с полом. Удобного локатора нет - ни id, ни класса. К тому же css/xpath локатор может меняться в зависимости от другой информации на странице. К тексту привязываться неудобно, потому что придется учитывать 3 возможных варианта текста - мужской, женский, не указан.

В SitePrism эта легко решается регулярным выражениям:

element :gender_label, "div", text: /^(Женский|Мужской|Не указан)$/

4. Генерация данных по шаблону

Из опробованных лично библиотек - Faker позволяет сгенерировать тестовые данные. В том числе, соответствующие регулярному выражению.

Faker::Base.regexify(/[a-z0-9]{10}/)

Результат: "31b0o05fyc"

5. Шаги в Cucumber

Я могу писать красивые, передающие суть, шаги.

Given(/^.+ have (\d+) apple.?$/) do |num| #some code end

Одинаково подойдет для:

I have 1 apple

и

I have 2 apples

We have 1 apple

You have 2 apples

Улучшенный вариант:

Given(/^(?:I|We|You) have (\d+) apple.?$/) do |num| #some code end

  • ?: означает , что группа (?:I|We|You) пассивная и не будет рассматриваться как параметр, тогда как группа (\d+) является активной и значение из нее будет использоваться в методе - переменная num.

Я могу легко расширять существующие шаги, не ломая тесты коллег.

Допустим, был шаг, проверяющие наличие двух полей - почты и пароля:

Given /^I see (\w+) and (\w+) on this page$/ do |email, password| # some code with email and password end

Я могу его расширить, если мне нужно еще несколько (сколько угодно!) полей.

Given /^I see (\w+) and ([^”]*) on this page$/ do |email, parts| params = parts.split(‘, ’) # some code with email and params end

Теперь я могу написать шаг:

Given I see email and password, author, date, subject on this page

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

When I search "apples?kind=2" When I search "apples"

Оба шага соответствуют регулярному выражению:

When(/^I search "(\w+(\?.+))"$/) do |url, query| # some code if query # some code else end

Хотя примеры приводились на руби, регулярные выражения не зависят от языка программирования, кроме, разве что, удобства работы с ними. Поэтому умение применять регулярные выражения не пропадет после перехода на любой другой язык, а также пригодится при работе с другими инструментами для тестирования (например, JMeter).