Всем привет! Про Cucumber есть много статей на Хабре и в интернете, но хочется вставить свои пять копеек.  Многие используют Cucumber, и я сам нахожу его довольно замечательной библиотекой. Мое личное мнение – каждому Java разработчику полезно быть знакомым с этой библиотекой наравне с JUnit фреймворком. Если ваши знания о Cucumber равны нулю, на Хабре есть отличные статьи, с которых лучше начать знакомство с этим инструментом  В своей статье я хочу дополнить данные руководства для начинающих. Показать, что я нахожу полезным в данной библиотеке, и привести примеры того, как Cucumber может выглядеть на реальных проектах из финансовой сферы.  Многие руководства по Cucumber начинают с рассказов о BDD и его связки с Cucumber. Поэтому есть стойкая ассоциация, что Cucumber можно использовать только, если ваша команда использует BDD. Это не так. Cucumber можно вполне успешно применять и для написания обычных интеграционных тестов. Я работаю в Технологическом Центре Дойче Банка на проекте, который разрабатывает софт для инвестиционного подразделения, и в качестве примера для статьи решил найти какую-нибудь open source библиотеку для управления торговыми заявками (ака matching engine), с уже готовыми интеграционными тестами, которые мы перепишем на Cucumber.  An order matching system – центральный компонент в электронных торговых площадках, которая управляет состоянием клиентских заявок на покупку/продажу чего-либо.  В результате поисков на Github мне выдался вот такой проект в топе. У него есть интеграционные тесты, которые написаны на JUnit.  Начинаем разбирать первый тест basicFullCycleTest. Два клиента ставят ордера на биржу на покупку и продажу, часть ордеров встречные (цена покупки/продажи пересекается).  Размер метода где-то 100 строчек, которые нужно прочитать, чтобы понять, что конкретно тестирует данный сценарий.  Теперь перепишем это на Cucumber.  Для начало добавляем Cucumber зависимости в Maven. Я использовал самую свежую на сегодня версию 5.4.2. Смотрим на JUnit интеграционный тест: было На каждый тест-кейс в JUnit создается некий промежуточный объект между тестовым сценарием и matching engine. Для Cucumber мы создаем класс, где будем описывать наши тестовые шаги и создадим этот тестовый объект для использования его в наших шагах. стало Cucumber перед каждым сценарием (подчеркиваю, сценарием, а не для всего feature файла, где может быть описано несколько сценариев) создает новый экземпляр класса, реализующий тестовые шаги. Если вы используете dependency injection, это также создает экземпляры объектов, которые вы хотите использовать, и вставит их во все реализации. Для каждого сценария используется новый экземпляр определения шагов и всех его зависимостей. Если вы хотите иметь какой-то статичный контекст между сценариями, то можно пользоваться статичными переменными. Обычно это может быть какое-то подсоединение к удаленной системе, которую вы тестируете. Если установление соединения происходит долго, тогда для улучшения скорости тестов можно устанавливать соединение во время первого сценария и сохранять его для последующих сценариев. Исследуем дальше тест на JUnit: Он создает ордер, посылаем его внутрь matching engine, ждем подтверждения, проверяем, что команда выполнилась без ошибок и никаких match событий не произошло.  Дальше в тесте создается еще один ордер. В этом шаге, как я понимаю, разработчику стало чуть лень прописывать проверки на все поля, поэтому обошлось просто проверкой кода возврата и отсутствуем сделок. Следующим шагом в тесте проверяется, как в контейнере выглядит текущий стакан ордеров для данного инструмента на конкретный момент. Теперь пример того, как я это переписал в Cucumber Так как у нас один и тот же тестовый сценарий выполняется дважды, но с разными инструментами в JUnit реализации, в Cucumber для этого я использую Scenario Outline. Благодаря этому, я могу внутри сценария использовать переменную <symbol>, и мой сценарий будет выполнен дважды, для двух разных инструментов. Теперь посмотрим на реализацию этих шагов в Glue-слое Отличия теперь в том, что мы не проверяем здесь matcher events, как в JUnit, а выделяем эту проверку в отдельный шаг. Реализацию проверки стакана ордеров я сделал в новом классе, чтобы показать, как реализации шагов можно (и нужно, когда их у вас становиться много) разносить по нескольким классам и как здорово в Cucumber работает dependency injection.  В данном шаге мы будем работать с таблицами. В последней версии Cucumber можно сразу распарсить таблицу и сконвертировать в какой-то ваш объект. Это позволяет избежать некрасивых обращений по индексу к элементам списка. Однако здесь я не буду приводить пример (надеюсь, меня простят за небольшую лень :-), да и текст статьи выходит довольно длинным) — об этой возможности хорошо рассказано тут.  Обратите внимание на container в классе. Это будет ссылка на тот же самый экземпляр, что и в OrderStepdefs. И все это делает Cucumber библиотека без каких-либо усилий с вашей стороны. Cucumber создаст экземпляр ExchangeTestContainer, после этого создаст экземпляры OrderStepdefs и OrderBookStepdefs и передаст им ссылку на созданный перед этим экземпляр ExchangeTestContainer. Конечный результат тестового сценария на Cucumber выглядит так: Я опустил какие-то моменты реализации — например, определение пользовательского типа {symbol}. Полную реализацию можно посмотреть у меня на github или если автор exchange-core библиотеки примет мой Pull Request, то в основном репозитории этой библиотеки. Выводы  На мой субъективный взгляд, тесты на Сucumber выглядят намного более читабельными, чем при реализации в JUnit. Другая возможность заключается в том, что это облегчает возможность вовлечения QA команды в работу над написанием новых сценариев.  Cucumber дает дополнительный уровень абстракции к вашим тестам на JUnit. Этот слой абстракции выделяет суть вашего сценария и отделяет его от реализации.  Java страдает многословием, и даже если вы дисциплинированно пишите комментарии, быстро вникнуть в длинный код через уже месяц может быть затруднительно.  Другим плюсом Cucumber является то, что он позволяет избежать полного переписывания ваших тестов в случае каких-то серьезных рефакторингов вашего API, при котором сценарии использования вашего компонента не изменились.  В данном примере у этой библиотеки кроме прямого API, есть REST API. При желании не должно составить большого труда написать другую реализацию glue-слоя для REST API. При этом сами Cucumber сценарии остаются теми же и должны будут также проходить.  Еще одно большое преимущество Cucumber для меня — это встроенная поддержка в современных IDE, таких как JetBrains Idea. Это сильно сказывается на комфорте и скорости разработки новых сценариев.  Вот небольшой список того, что умеет Idea из первого, что приходит на ум:  Если вы используете какие-то свои доморощенные скрипты, то польза от перехода на Cucumber будет еще и в том, что новому человеку в команде намного легче будет влиться в работу, если используются известные и популярные библиотеки, нежели чем разбираться, где у вас в проекте парсер для ваших тестовых скриптов или как расширить существующий тестовый самописный фреймворк какими-то новыми конструкциями. Не забывайте об этом.  Какой подход выбрать — решать вам. Для кого-то это покажется еще одним лишним слоем и технологией в проекте. Кому-то может понравится лаконичность конечных сценариев для чтения.  Выбор всегда за вами.  Спасибо, что дочитали до конца. Java разработчик