Реализация Cucumber Expressions
В третьей версии Cucumber JVM стал доступен Cucumber Expressions — простой язык выражений для поиска подстрок в тексте.
В отличие от регулярных выражений этот язык оптимизирован для удобочитаемости, что в контексте Cucumber’а имеет больший смысл. Если вам нужна гибкость, то по-прежнему можно воспользоваться регулярными выражениями.
Например, у нас есть следующая фича:
# language: ru Функция: Передача аргументов различных типов Сценарий: * передадим в метод шага целое число 15 * передадим в метод шага "текст" * передадим в метод шага hello
Для получения аргументов из неё можно воспользоваться следующим описанием шагов:
@Допустим("передадим в метод шага целое число {int}") public void giveInt(Integer int1) { System.out.println(int1); } @Допустим("передадим в метод шага {string}") public void giveString(String string) { System.out.println(string); } @Допустим("передадим в метод шага {word}") public void giveWord(String string) { System.out.println(string); }
Как видно из примера Cucumber Expressions состоит из двух фигурных скобок с указанием типа передаваемого значения.
«Из коробки» доступна передача следующих типов:
- {int}
- {float}
- {string}
- {word}
- {biginteger}
- {bigdecimal}
- {byte}
- {short}
- {long}
- {double}
{string} соответствует строке в кавычках, а {word} — одному слову без кавычек (на момент написания статьи в выражение {word} можно передавать только слова, написанные латинскими буквами).
Можно создать свой тип данных, например мы хотим передавать из фичи объект класса LocalDate:
# language: ru Функция: Передача пользовательского типа Сценарий: * передадим в метод дату 01.06.2018
@Допустим("передадим в метод дату {localdate}") public void передадим_в_метод_дату(LocalDate localdate) { System.out.println(localdate.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"))); }
Для этого в пакете, указанном в glue, необходимо создать класс, реализующий интерфейс TypeRegistryConfigurer, и через него добавить свой тип данных в реестр:
public class TypeRegistryConfiguration implements TypeRegistryConfigurer { @Override public Locale locale() { // требуется только для определения формата разделителя в float и double return new Locale("ru"); } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { // добавление в реестр определения необходимого типа typeRegistry.defineParameterType(new ParameterType<>( // название параметра, используемое в определении шага: "localdate", // регулярка, для поиска необходимого значения в фиче: "[0-9]{2}.[0-9]{2}.[0-9]{4}", // тип параметра: LocalDate.class, // функция, преобразующая входящую строку к нужному типу (Transformer<LocalDate>) s -> { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); return LocalDate.parse(s, formatter); } )); } }
Класс, реализующий интерфейс TypeRegistryConfigurer, в проекте должен быть один, иначе будет выброшено исключение.
Также Cucumber Expressions позволяет в скобках указать необязательный текст:
@Допустим("Hello, world(s)!") public void getHello() { System.out.println("Hello world!"); }
Внутри скобок нельзя использовать пробелы (на момент написания статьи поддерживается только латинский алфавит).
Альтернативный текст задается через косую черту:
@Допустим("основной/альтернативный текст") public void getAlternative() { System.out.println("Hello world!"); }
# language: ru Функция: Основной и альтернативный текст Сценарий: * альтернативный текст * основной текст
Экранировать {} и () можно обратной косой чертой.
В одном определении шага нельзя одновременно использовать Регулярные выражения и Cucumber-выражения.
Отказ от XStream
В первой и второй версии Cucumber для определения типа передаваемых данных использовались регулярные выражения и библиотека XStreamsConverters. В третьей версии Cucumber разработчики отказались от использования библиотеки XStreamsConverters.
Обоснованием для отказа от XStreamConverters была плохая документация, отсутствие возможности использования сторонних мапперов объектов, а также отсутствие поддержки Java 9.
Аннотации Delimiter, Format, Transformer и другие аннотации из XStream больше не работают. Вместо них теперь необходимо использовать ParameterType или DataTableType.
DataTable
Тип данных DataTable также подвергся изменениям.
Как и в предыдущих версиях Cucumber 3 без проблем справляется с преобразованием DataTable с одним столбцом в List, с двумя столбцами в Map и т.п. Но это работает, только если преобразовывать данные в один из следующих типов: String, Integer, Float, Double, Byte, Short, Long, BigInteger или BigDecimal.
Если же вы хотите создать из DataTable объект какого-то другого класса, то вам, как и в случае пользовательского типа данных, необходимо написать свой преобразователь:
# language: ru Функция: Передача пользовательского типа через DataTable Сценарий: Допустим у нас есть пользователи | Василий | Чапаев | 09.02.1887 | | Пётр | Исаев | 23.02.1890 |
import java.time.LocalDate; public class User { private String firstName; private String lastName; private LocalDate birthDay; public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public LocalDate getBirthDay() { return birthDay; } public void setBirthDay(LocalDate birthDay) { this.birthDay = birthDay; } @Override public String toString() { return "User{" + "firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", birthDay=" + birthDay + '}'; } }
@Допустим("у нас есть пользователи") public void у_нас_есть_пользователи(List<User> users) { System.out.println(users); }
Преобразователь добавляется в реестр таким же образом, как и в примере с пользовательским типом данных:
public class TypeRegistryConfiguration implements TypeRegistryConfigurer { @Override public Locale locale() { return new Locale("ru"); } @Override public void configureTypeRegistry(TypeRegistry typeRegistry) { // в этот раз в реестр добавляем DataTableType typeRegistry.defineDataTableType(new DataTableType( User.class, (TableRowTransformer<User>) list -> { User user = new User(); user.setFirstName(list.get(0)); user.setLastName(list.get(1)); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy"); user.setBirthDay(LocalDate.parse(list.get(2), formatter)); return user; } )); } }
Before и After Step Hooks
Еще одно нововведение — пре и пост степы. Теперь можно определять хуки, которые будут вызываться до и/или после каждого шага сценария.
Step hooks работают по тем же правилам, что и хуки, относящиеся к уровню сценария:
- на хуки можно навешивать тэги для их запуска только в определенных сценариях;
- можно устанавливать очередность выполнения хуков;
- AfterStep выполнится даже если шаг, после которого он должен был выполниться, сломается.
# language: ru Функция: Фикстуры @hooks Сценарий: вызов фикстур до и после сценария, а также перед и после каждого шага Дано Первый шаг Когда Второй шаг Тогда Третий шаг @only_scenario_hooks Сценарий: вызов фикстур только до и после сценария Дано Первый шаг Когда Второй шаг Тогда Третий шаг @only_step_hooks Сценарий: вызов фикстур только перед и после каждого шага Дано Первый шаг Когда Второй шаг Тогда Третий шаг
// секция not написана исключительно ради демонстрации // выполнится только перед сценариями с тэгами hooks и only_scenario_hooks @Before(value = "(@hooks or @only_scenario_hooks) and not @only_step_hooks") public void before() { System.out.println("before scenario"); } // выполнится перед каждым шагом в сценарии с тэгом only_step_hooks @BeforeStep(value = "@only_step_hooks") public void beforeStep() { System.out.println("before step"); } // выполнится после каждого шага в сценарии с тэгом only_step_hooks @AfterStep(value = "not(@hooks or @only_scenario_hooks) and @only_step_hooks") public void afterStep() { System.out.println("after step"); } // выполнится только после сценариев с тэгами hooks и only_scenario_hooks @After(value = "@hooks or @only_scenario_hooks") public void after() { System.out.println("after scenario"); }
В заключение хотелось бы сказать, что даже если вы использовали в своих проектах возможности XStream и с переходом на новую версию Cucumber необходимо будет внести небольшие доработки, рекомендую это сделать. Cucumber поддерживается и активно развивается, а новые фичи делают его использование все более гибким и понятным.
Ссылки:
Примеры из статьи
Моя статья по первой версии Cucumber JVM
ссылка на оригинал статьи https://habr.com/post/422651/
Добавить комментарий