Не так давно дошли руки до рассмотрения Java 8. После ознакомления с Java 8 Tutorial и Java 8 Stream Tutorial интересно стало поэксперементировать и понять, чего нам ждать от фундаментальных нововведений, а также - смогут ли они хоть как-то упростить и без того нелегкую судьбу автоматизаторов. С подробными результатами эксперимента можно ознакомиться в моем блоге.
Начнем пожалуй с примера, который был приведен в одной из недавних тем. Все мы так или иначе сталкивались с проблемами ожиданий каких-либо элементов на странице. В качестве одного из возможных решений может выступить реализация кастомного findElement:
Тут мы используем лишь одно условие - ExpectedConditions.visibilityOfElementLocated. Для common сценариев этого может быть вполне достаточно. Но вот если нам потребуется нечто универсальное, то без велосипедов явно не обойтись.
Что же нам предоставляет Java 8? Для решения данной задачи мы сможем воспользоваться ссылками на методы (да-да, именно на методы), а также - функциональными интерфейсами.
Собственно, помимо локатора и таймаута, на вход подается функция 1 input (By
) / 1 output (ExpectedCondition<WebElement>
) аргументов. К слову, это может быть и кастомный функциональный интерфейс.
Если мы внимательно присмотримся к сигнатуре и типу возвращаемого значения наиболее интересных методов класса ExpectedConditions, мы заметим, что они идеально подходят нашей функции. Как итог, при помощи специального символа :: мы можем сослаться на статические методы нужного нам класса, и передать их в качестве одного из параметров findElement.
Это и есть так называемые methods’ references. К слову, мы можем использовать ссылки не только на статические методы, но и обращаться к методам конкретных объектов. Насколько проще стало писать универсальные методы, не так ли?
Помимо этого, вы наверняка заметили не менее интересную конструкцию - Optional. Это встроенный функциональный интерфейс, который идеально подходит для валидации объектов, которые потенциально могут быть null. В случае NullPointerException наш Optional.ofNullable(Object) прыгнет прямо в orElse блок, который предоставит нам некое дефолтное значение. Помимо этого, данный встроенный функциональный интерфейс, как и любой другой, предоставляет нам доступ к новым возможностям Java 8, одной из которых является гибкая фильтрация с использованием lambda expressions. Таким образом, при помощи техники methods chaining, мы проверили объект на null, отфильтровали по неотрицательным числам, и предоставили дефолтное значение на случай не прохождения валидации. Полезно? Поехали дальше.
В качестве альтернативы циклам в Java 8 пришли streams, которые позволяют нам писать код еще более гибко. К слову, разработчики предусмотрели также и parallel streams (думаю название говорит само за себя).
В качестве примера приведу реализацию получения списка текстовых айтемов из коллекции веб-элементов.
Ничего сверхестественного: обычный циклический обход элементов с пересохранением избавленного от пробелов текста в новый список. Теперь давайте посмотрим, как будут выглядеть streams:
Как видите, никаких промежуточных коллекций больше не требуется. Обращение к stream() подразумевает тот самый циклический обход. map(lamda expression) позволяет преобразовать каждый элемент объекта коллекции в новую сущность. А collect с шикарным utility классом Collectors вернет новую коллекцию замапленных ранее объектов. К слову, на выходе мы можем получить что угодно, даже Map. Удобно? Поехали дальше.
Последний, более сложный пример, завязанный на все тех же streams. В недавней теме я приводил пример реализации кастомных темплейтов при помощи Mustache. Собственно, информация для заполнения бралась из внутренностей TestNG results структуры, которая, к слову, является не очень то и тривиальной.
Для формирования нужного репорт скоупа мы проходили по сьютам, попутно выгребая результаты, которые также желательно было еще и отсортировать при помощи кастомных Comparators. Все это дело потом сохранялось в Suite / TestResult сущности для дальнейшей обработки. Выглядело это приблизительно так:
И это только малая часть того, что обычно нужно выгр■■■■■ для формирования репорта. Теперь давайте посмотрим на Java 8 модификацию:
Как вы уже поняли, от промежуточных коллекций мы избавились (stream). Стейтменты (if) были заменены фильтрами (filter). Итоговые сущности подготавливались коллекторами (Collectors.toList()), с предварительным преобразованием объектов (map(labmda)). Апофеозом тут предстали кастомные Comparators, реализованные прямо на лету при помощи sorted + lambda. И это только часть возможностей streams.
Конечно, для начинающих или old school разработчиков подобные фичи могут показаться весьма неочевидными или даже сложными для восприятия. Но лично для себя, просмотрев приведенный выше материал, нашел много полезных вещей, которые смогут упросить разработку различных компонентов. Будит ли все это полезно именно Вам? It’s up to you.