Практика BDD в автоматизации QA — гайд по Cucumber/Gherkin — вопросы на собеседовании по BDD/Cucumber
Сейчас узнаем, что такое BDD и как оно работает; плюсы-минусы и подводные камни; как в одной международной компании выбрали BDD и не пожалели; постараемся запомнить лучшие практики BDD; ну и посмотрим на примеры BDD на Gherkin (много).
Содержание
- Что такое BDD в QA
- Фреймворки для BDD
- Как мы выбрали BDD и не пожалели
- Плюсы BDD
- Минусы BDD
- Что такое Gherkin
- Ключевые слова Gherkin
- Как мы переходили на Gherkin
- Практика в Cucumber
- Features в Cucumber
- Контрольные вопросы / Собеседование Cucumber
Что такое BDD-разработка, как она применяется в QA
“Разработка через поведение” (BDD — Behavior Driven Development) в QA — это легко читаемые человеком, не владеющим языками программирования, описания требований к продукту — как основа процесса тестирования. Такие тесты являются реюзабельными — то есть могут применяться многократно без больших изменений, но если все-таки понадобится изменить какие-то детали, это будет легко. BDD-тесты предназначаются, в основном, для проверки функциональных компонентов, и далее применяются повторно на более высоком уровне тестирования, что ускоряет пайплайн.
Самое частое применение BDD-метода — это UAT-тесты (User Acceptance Tests, то есть пользовательское или приемочное тестирование). Такие тесты строятся на user story (что это?) и на бизнес-требованиях, и имеют особенность: они пишутся в форме, хорошо воспринимаемой человеком, как бы на обычном языке. Разумеется, “обычный язык” здесь следует понимать ограниченно, поскольку в нем все-таки заданы рамки, есть строго определенные вещи. Основа, или “скелет” тестов может быть написан product owner-ом (или владельцем продукта — здесь можно почитать, кто это?), или бизнес-аналитиком.
BDD-тесты пишутся так, чтобы их мог прочесть человек, не знающий языков программирования (но знающий английский, хотя бы минимально)
Первый шаг, предпринимаемый командой при внедрении BDD — создать некие общие определения, понимаемые стейкхолдерами (кто это?), экспертами в какой-то области (domain experts), разработчиками, и конечно тестировщиками. Этими определениями будут описываться основные модули продукта, события, и ожидаемые (пользователями) результаты. То есть сначала создается набор терминов, согласованный всеми участниками. Это важно, потому что это фактически определяет успешность внедрения BDD.
Основной позитив от BDD состоит в том, что практически все члены команды, как технические специалисты, так и “другие” — способны быстро понять и оценить результаты тестов, и в целом им легче работать с такими тестами.
Какие фреймворки применяются в BDD?
- Во первых, Cucumber
- Quantum (это для Java на Андроиде и/или iOS)
- SpecFlow (это для .NET)
- Jbehave (это для команды, овладевшей Groovy/Kotlin/Scala)
- Codeception (для PHP)
Как мы выбрали BDD и не пожалели
На начальном этапе, когда проект только стартовал, когда кто-то предлагает переключиться на новую методологию BDD, опытные лиды учитывают, что начальная подготовка BDD-проекта почти наверняка будет дольше и сложнее, чем все привыкли на старых методологиях. Просто потому что раньше все шло “по накатанной” — есть более-менее стандартный проект; с какой-то автоматизацией; его предполагаемая структура более-менее известна; все знают что делать; берется фреймворк автоматизации, известный вдоль и поперек, настраивается веб-драйвер, или API-шлюз, выбирают язык программирования из короткого списка, ну и пишут первые тесты.
С BDD-проектом так вряд ли получится так просто, сначала понадобится больше времени и усилий. Этапы выбора языка и прочее остаются, и добавляется “экстра” — о чем речь шла выше, “общий словарь терминов”, который будет понятен буквально каждому члену команды, что иногда непросто; по опыту, этот шаг занимает много времени.
BDD лучше подходит для долгосрочных проектов, особенно корпоративных, для крупных заказчиков. В таких проектах плюсы BDD проявятся. Если же проект запланирован на год или меньше, то “лучше идти по пути без BDD” — так, видимо, будет проще, быстрее, и дешевле.
Если проект “большой”, корпоративный, то есть подходит для BDD — то скорее всего для фронтэнда вполне сгодятся имеющиеся тестовые инструменты; условно для прокликивания веб-элементов можно применять стандартную связку типа Browserstack+Selenium. Для бэкэнда можно Postman+Smartbear.
BDD подходит для крупных долгосрочных только-начатых проектов потому, что там обычно большое количество реюзабельных тестовых компонентов, шагов и функций, которые должны быть понятны всем членам QA-команды, разбросанной по миру. Но BDD вряд ли идеально подойдет для сложных проектов с большим количеством уже написанных модулей, ибо рефакторить имеющийся код “под BDD” может быть довольно-таки затратно по времени.
Плюсы BDD
- Поддерживается английский, понятный каждому тестировщику — т.н. Simple English с ограниченным словарем, и + еще 70 языков (включая русский, разумеется)
- Тесты по идее понятны любому члену команды
- Позволяет поддерживать в команде высокий уровень вовлеченности и понимания продукта
- Экономятся деньги и усилия, при правильном внедрении
- QA-персонал прокачивает свой уровень компетенций, интуитивно обучаясь
Минусы BDD
- Медленнее деплой
- Могут быть проблемы на этапе деплоя
- Много как бы “лишних” классов, функций, этапов, с точки зрения некоторых педантов
- Нужна очень хорошая коммуникация в команде, и очень опытные лиды
- Проект в целом получается “сложнее”, если нужен рефакторинг существующего кода
- Документация…
Что такое Gherkin
Это так называемый business-readable язык программирования, описывающий бизнес-поведение, на котором пишется “скелет тестов”, без глубокого погружения в детали имплементации функций. Геркин — это как бы “простая речь”, описывающая use-кейсы (что это?), и позволяющая логически описать тесты действий пользователя. Gherkin основан на Словаре Treetop, существующем на 70 языках. Поэтому вся команда может писать тесты на любом из этих 70 языков.
Но — в большинстве случаев все-таки пишет на Basic English.
Ключевые слова Gherkin
- Feature
- Background
- Scenario
- Scenario Outline Examples
- Given
- When
- Then
- And
- But
Пример синтаксиса Gherkin:
Feature: Title of the Scenario Given [Preconditions or Initial Context] When [Action/Event or Trigger] And [Join] But [Join] Then [Expected output/ Result]
Как мы переходили на Gherkin
Наша dev-команда не имела никакого опыта с BDD. Во всех наших проектах мы не задумывались о BDD, просто потому что считали “это что-то несерьезное”. Убедила нас параллельная QA-команда из другой страны, продемонстрировав на практике, как это делается, и чем эффективно.
Коллеги продемонстрировали, как их один тестировщик может писать в среднем за день 10 тестов бэкэнда. Это показалось интересным. Также показалось практичным то, что наш новый большой проект требовал проведения всех возможных автотестов (бекэнд, фронтэнд, производительности, безопасности), а команда интернациональная. На этом этапе мы уже склонились к BDD и Cucumber — как популярному фреймворку в этой сфере, с бесплатными обновлениями и (уже) большим комьюнити. Выбран был также фреймворк Serenity для управления тестами и репортов, и Kotlin как “основной” ЯП. Планировалось автоматизировать тесты функциональные/интеграционные/приемочные/сквозные, то есть как бэкэнд, так и фронтэнд.
Проект был достаточно сложным, в QA работали еще параллельно команды из Южной Азии (Индонезия) и Восточной Европы (Словакия). Это было решение для интернет-банкинга, клиенты — банки, корпорации и частные лица.
В первые месяцы QA-команда наполнялась с трудом, т.к. на рынке ощущался дефицит тестировщиков-автоматизаторов с опытом, особенно в Cucumber/Gherkin. Из-за недостатка тестировщиков мы были вынуждены набирать людей вообще без опыта в автоматизации. И тут-то сказалось удобство BDD и простота синтаксиса Gherkin, особенно что касается индонезийских тестировщиков, плохо владеющих ЯП, но имевших опыт в написании feature-файлов (изначальный “скелет” тестов), и владевших Basic English. Они сильно помогли в начале, и благодаря им остальные члены QA-отдела смогли написать и автоматизировать нужные тесты.
Далее со “скелетом” поработали бизнес-аналитики, расширили его, особенно в части приемочных тестов. Вся переписка в QA-команде была на Basic English, как и сами тесты. Тестировщики-индонезийцы разговаривали “на своем” с ручными тестировщиками, тоже индонезийцами, которые локально работали с manual-тестами. Опытные лиды знают, какой проблемой бывает коммуникация между людьми в remote-командах из далеких, иногда весьма экзотических, стран; уровня native-english ожидать не приходится, обычно это Basic English с резким акцентом. Самые блестящие тестировщики-индонезийцы сначала страдали от непонимания, что им делать, особенно это касалось бизнес-требований; manual-тестировщики сначала вообще не могли понять, чего от них хотят; BDD/Gherkin помог в таких ситуациях, стал как бы посредником, благодаря Basic English, который знают, в общем-то, все люди в ИТ — простым языком описывалось, что должно быть протестировано, и почему, и что получится в результате.
Итак, BDD/Gherkin годен, если:
- Новый крупный проект
- Требуется оперативность внесения правок (новых требований)
- QA-команды удаленные и плохо понимающие друг друга
- Бизнес-аналитики тоже бывают “местными” и их бывает мало
- В команде много людей без технического бэкграунда и много местных manual-тестеров
Практика — проект в Cucumber
Как выглядит проект в Cucumber, как выглядят автотесты в Cucumber, и чем они отличаются от обычных, не-BDD-тестов
В “стандартном”, не-BDD-проекте у нас стандартно был один Test Class (тело теста) и один Step Class (логика). В BDD-проекте обычно надо “делить” эти классы на дополнительные вложенные.
В нашем BDD-проекте Test Class был разделен на feature-файл и сам тест, а Step Class разделили на Step Definition и Steps.
Ниже показаны примеры, как это выглядит.
Feature-файл на Gherkin:
Scenario Outline: Creating requests with absence of mandatory fields When I create POST request for ACCOUNT without mandatory <param> Then expected status code for request is 400 Then I should get status code ERRORExamples: | param | | ID | | NAME | | CODE |
Создание запросов при незаполненных обязательных полях
Здесь “ACCOUNT”, “400”, “ERROR” — это параметры этапов; <param> — для повторения этапов.
Файл Step Definition: Функции с аннотациями (объяснение текста в feature-файле — логика, как мы помним, вынесена в отдельный файл)
Текст связан с кодом через аннотацию (с применением Regex-аннотации):
@When(“^I create POST request for (.*) without mandatory (\\<?\\w+\\>?)$”) fun i_create_post_without_param(endpoint : Endpoints, param : String) { baseSteps.createPOSTRequest(URL.API_GATEWAY, path = endpoint, bodyContent = JsonGenerator().generateJSON(accountGroup), authorization = baseSteps.token) }@Then(“^expected status code for request is (\d+)$”) fun status_code_for_request(statusCode : Int) = baseSteps.checkStatusCode(statusCode)@And(“^I should get status code (.*)$”) fun get_status_code(statusCode : ResponseMessages) = baseSteps.validateStatusCode(statusCode)
Файл Steps: — Тестирование логики в StepDefinition-файле
Файл Test: “склеивание” feature-файла и StepDefinition-файла (это делает glue-параметр)
@RunWith(CucumberWithSerenity::class) @CucumberOptions( features = [“src/test/resources/features/film/create.feature”] plugin = [“pretty”], glue = [“com.name.stepdefinitions.film”, “com.name.stepdefinitions.common”])class Create
В glue-параметре может быть больше одного Steps / Definitions, но в Feature-файле должна быть только одна функция.
Features в Cucumber + примеры
Итак, базовые понятия есть, приступим к практике.
Background (Предыистория)
Часто бывает, что этапы повторяются во всех сценариях, связанных с Feature-файлом.
Если этапы повторяются в каждом сценарии, это значит, что эти этапы не очень важны для описания сценариев; это получаются неважные этапы. Их можно как бы “отодвинуть назад”, сгруппировав в секции Background.
Это позволяет внести некий контекст в сценарий. В секции может быть несколько этапов, которые выполняются перед каждым сценарием. Background вставляется перед первым Scenario/Example, с тем же отступом:
Background: Given I get token for admin from NETFLIX_EU appScenario: Searching fantasy film When …… Then …… And ……Scenario: Searching anime from JAPAN for each region When ……Scenario: Searching anime from JAPAN for ASIA region When ……
Regex’ы в аннотациях
В Cucumber есть альтернатива “классическим” Regex’ам (более интуитивные регексы, как считают создатели Cucumber). Но в целом, бывает достаточно “классических”.
@And(“^I have (\d+) cucumbers in my belly$”) fun countCucumbers(value : Int) = baseSteps.getCucumber(value)
Здесь:
Выражение [ \d+ ] допускает только целый (integer) параметр в feature-файле; когда пользователь вводит например 2,5 — выдается сообщение об ошибке в feature-файле.
Выражение [ @And(“^ ] — в каждом из элементов ( .* )-массива. “Точка со звездочкой” ( .*) служит как замена “любого символа” (так называемый “джокер”)
(Вообще, в feature-файле допустимы любые символы/цифры/знаки).
Выражение в скобках [ (was|wasn’t) ] после слова response можно писать только в такой форме (was или wasn’t) — другое написание будет некорректным.
@And(“^I should get status code (\\<?\\w+\\>?)$”)
Regex-выражение [ \\<?w+\\>? ] — когда два разных типа строк, первая это стандартная строка ( “test” ), вторая — если она параметр, типа “<test>” то есть с вложенными символами. < and > — необязательный параметр.
Подробнее см. раздел документации по Regex.
Таблицы данных (Data Tables)
Таблицы данных в Cucumber применяются в Scenario Outline, когда тестовый сценарий повторяется несколько раз. Тогда не нужно инициализировать таблицы данных, Cucumber делает это автоматически:
Scenario Outline: Testing endpoint accessibility for update filmGiven I get token for <user> from <app> app When I create PUT request for FILM with all parameters Then expected status code for request is 400 And I should get status code ERRORExamples: | user | app | | maker | NETFLIX_EU | | admin | NETFLIX_AS | | regular | NETFLIX_NA |
Иногда нужно отправить еще какие-то параметры в тест-кейс, в котором шаги не будут повторяться.
And in response was displayed parameters: | name | start_date | type | episodes |@And(“^in response (was|wasn’t) displayed parameters?$”) fun response_display_parameters(visibility : String, data : DataTable) = baseSteps.getParams(data)@Step fun getParams(parameterTable : DataTable) : Map<String,Any> { val tableMaps : MutableList<MutableMap<String,String>> = parameterTable.asMaps() val loadedValues = tableMaps[0] val transforms = tableMaps[1] return loadedValues.entries.map { (param,valueKey) -> val loadedValue = if (valueKey.isNullOrEmpty()) "" else DataLoader.getValue(valueKey) val transform = transforms[param] val finalValue = processValueTransform(transform.toString(),loadedValue) Pair<String,Any>(param,finalValue) }.toMap() }
Как видим здесь, надо «прописать» этот параметр и указать тип DataType в StepDefinition-файле; это дольше и сложнее, но потом экономит время.
Больше примеров — здесь.
Как выглядят тесты на Gherkin в полностью русскоязычных проектах, можно посмотреть здесь.
***
Контрольные вопросы / Собеседование QA по Cucumber
Что такое Cucumber?
Cucumber — это огурец! А для тестировщика Cucumber — это основной рабочий фреймворк, если он работает по BDD.
А что такое BDD? Зачем нужно BDD?
BDD — это “разработка через тестирование”, специфическая Agile-методология для «разрушения технического и языкового барьера» между бизнес-аналитиками, владельцами продукта, разработчиками и тестировщиками.
Как связаны BDD и TDD?
TDD — это Test Driven Development, разработка через тестирование”. BDD-методология возникла как “продолжение” TDD. BDD основана на принципах TDD. Здесь чуть подробнее о TDD.
А чем отличается BDD и TDD?
Поскольку BDD это развитие идеи TDD, то BDD как бы направлен на устранение проблем, которые не может решить TDD. Подробный материал о BDD и TDD по ссылке.
Что такое Геркин?
Геркин (Gherkin) — это маленький соленый огурец из банки, употребляемый в качестве закуски. А для тестировщика Gherkin — это специфический язык программирования, который выглядит “почти как человеческий язык”, понятный не-технарям, при этом сохраняющий “формальность” классических языков программирования — это нужно для автоматической обработки такого текста, то есть применения в автоматизированных тестах.
Другое определение Gherkin: легко читаемый язык описания желаемого поведения системы.
Как определить, что это сценарий на Gherkin?
В структуре документа используются отступы — пробелы и табуляция, как в Python, но текст выглядит как бы “менее формально” чем в Python. Каждая строка начинается с ключевого слова и далее в ней описывается какое-то одно условие или действие. Примерно так это выглядит в русском варианте:

Что должно быть в Feature-файле?
“Высокоуровневое” описание приложения. Первая строчка feature-файла должна начинаться с ключевого слова “Feature”, далее идет описание функции. В этом файле обычно несколько сценариев. Файл должен иметь расширение *.feature.
Какие ключевые слова Gherkin знаете?
Наиболее часто применяемые:
- Given
- When
- Then
- And
Зачем нужен файл Scenario Outline в Cucumber?
Это файл с параметризацией сценариев. Когда один сценарий “принимает” много наборов тестовых данных, а этапы остаются те же.
А какие (еще) языки программирования поддерживает Cucumber?
Практически все применяемые в QA, типа Java, Python (есть библиотека Behave), есть Cucumber.js.
Обычно Feature-файлы пишутся на Gherkin, а StepDefinition-файлы — на стандартных ЯП.
(Разумеется, Cucumber может интегрироваться с Selenium.)
Зачем нужен файл Step Definition в Cucumber?
Выполняет тест по шагам-этапам и проверяет результаты. Каждый шаг (выполнения) в Feature-файле соответствует какому-то методу в StepDefinition-файле.
Сколько сценариев может быть в Feature-файле?
Максимум 10, обычно их меньше.
Сколько шагов (этапов) может быть в одном сценарии?
Не более 3, или 4.
Может ли Cucumber работать с Selenium Webdriver?
Да, может, здесь туториал (англ).