Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Ruby
Code

Паттерн Page Objects в Ruby для пользователей Capybara

by
Length:LongLanguages:

Russian (Pусский) translation by Marat Amerov (you can also view the original English article)

Final product image
What You'll Be Creating

Что такое Page Objects?

Это шаблон проектирования для инкапсуляции разметки и взаимодействия с страницами - в частности, для рефакторинга функциональных спеков. Это комбинация двух очень распространенных методов рефакторинга: Extract class и Extract method, которые не должны происходить одновременно, при этом есть возможность постепенно вести разработку извлекая все в класс через новый Page Object.

Этот метод позволяет писать высокоуровневые функциональные спеки, которые являются очень выразительными и краткими. В некотором смысле, они являются приемочными тестами на языке приложения. Вы можете спросить, разве спеки написаные с Capybara не являются высокоуровневыми и выразительными? Конечно, для разработчиков, которые ежедневно пишут код, спеки Capybara читаются просто отлично. Являются ли они краткими из коробки? На самом деле, нет!

Когда вы смотрите на эти примеры функциональных спеков, где вы видите возможности сделать улучшения, и как вы можете извлечь информацию, чтобы избежать дублирования? Кроме того, достаточно ли этого уровня для легкого моделирования пользовательских историй и для понимания нетехническими пользователями?

На мой взгляд, есть несколько способов улучшить это и сделать всех довольными разработчиками, которые могут избежать возини с деталями взаимодействия с DOM при применении ООП и другими членами команды, которые не занимаются кодингом, не испытывая проблем с переходом между историями пользователей и их тестми. Последний момент конечно приятен, но самые важные преимущества в основном связаны с тем, что ваши DOM-взаимодействующие спеки становятся более надежными.

Инкапсуляция - ключевое понятие в Page Objects. Когда вы пишете свои функциональные спеки, вы получаете стратегию для извлечения поведения, которое проходит через тестовый флоу. Для повышения качества кода вы хотите захватить взаимодействие с определенными наборами элементов на ваших страницах, особенно если вы натыкаетесь на повторяющиеся шаблоны. По мере того, как ваше приложение растет, вам нужен подход, который позволяет избежать распространения этой логики во всех спеках.

«Ну, разве это не перебор? Капибара прекрасно читается!» Что вы говорите?

Спросите себя: почему бы не иметь все детали реализации HTML в одном месте, имея более стабильные тесты? Почему тесты на взаимодействие с UI не должны быть такими же, как тесты для кода приложения? Вы действительно хотите остановиться на этом?

Из-за каждодневных изменений ваш код Capybara уязвим, когда он распространяется повсюду - он вводит возможные точки отказа. Предположим, что дизайнер хочет изменить текст на кнопке. Не сложно, не так ли? Но хотите ли вы адаптироваться к этим изменениям в одной центральной области для этого элемента в своих спецификациях или вы предпочитаете делать это повсюду? Я так и думал!

Существует множество рефакторингов для ваших функциональных спеков, но Page Objects предлагает самые чистые абстракции для инкапсуляции поведения пользователя на страницы или более сложных сценариев. Вам не нужно симулировать поведение для всей страницы, а сосредоточиться на существенных фичах, которые необходимы для пользовательских сценариев. Не нужно переусердствовать!

Приемочные тесты / Фича спеки

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

О чем мы здесь говорим? Приемочное тестирование обычно выполняется на более позднем этапе разработки проектов, чтобы оценить, разрабатываете ли вы что-то ценное для своих пользователей, владельца продукта или другого заинтересованного лица. Эти тесты обычно запускаются клиентами или вашими пользователями. Это какая-то проверка выполнения требований. Существует что-то вроде пирамиды для всех видов тестовых слоев, а приемочные тесты находятся на самом верху. Поскольку этот процесс часто включает нетехнических людей, язык высокого уровня для написания этих тестов является ценным достоянием для общения.

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

Такие инструменты, как Capybara, помогут вам избежать выполнение этого вручную, что означает, что вам редко придется открывать браузер для проверки функционала вручную. С такими тестами, вам понравится как можно больше автоматизировать эти задачи и тестировать взаимодействие через браузер при написании утверждений на страницах. Кстати, вы не используете get, put, post или delete, как вы делаете со спеками запросов.

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

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

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

Capybara

Может, нам стоит это сделать и побыстрее. Эта библиотека описывает себя как «Фреймворк для приемочного тестирования веб-приложений». Вы можете имитировать взаимодействие пользователей с вашими страницами с помощью очень мощного и удобного для домена языка. По моему личному мнению, RSpec в паре с Capybara предлагает лучший способ написать свои фича спеки на данный момент. Он позволяет вам посещать страницы, заполнять формы, нажимать на ссылки и кнопки, а также искать разметку на ваших страницах, и вы можете легко комбинировать все виды этих команд для взаимодействия со своими страницами через ваши тесты.

В основном вы можете не открывать браузер самостоятельно, чтобы тестировать этот материал вручную большую часть времени, что не только менее изящно, но и намного более трудоемко и подвержено ошибкам. Без этого инструмента процесс «наружного тестирования», который вы передадите из высокоуровневых тестов в свои юнит тесты, будет намного более болезненным и, возможно, поэтому будет игнорироваться.

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

Как?

Давайте рассмотрим два простых примера фича спеков, которые позволяют M создавать секретные миссии, которые затем могут быть завершены.

В разметке у вас есть список миссий, и успешное завершение создает дополнительный класс, completed в этом li конкретной миссии. Просто, да? В качестве первого подхода я начал с небольших, очень распространенных рефакторингов, которые извлекали общее поведение в методы.

spec/features/m_creates_a_mission_spec.rb

spec/features/agent_completes_a_mission_spec.rb

Хотя, конечно, есть и другие способы работы с такими вещами, как sign_in_as, create_classified_mission_named и т. д., Легко понять, как быстро эти вещи могут начать утомлять и накапливаться.

Я думаю, что спецификации, связанные с UI, часто не получают обьектно ореинтированного подхода, который им нужен. Они имеют репутацию приносящих слишком мало удовольствия, и конечно разработчики не очень любят, когда они много работают с разметкой. На мой взгляд, это делает еще более значимым DRY для этих спецификаций и далает их выразительными, при добавлении нескольких Ruby классов.

Давайте сделаем небольшой волшебный трюк, где я сейчас скрою реализацию Page Object, и покажу вам конечный результат, примененный к фича спекам выше:

spec/features/m_creates_a_mission_spec.rb

spec/features/agent_completes_a_mission_spec.rb

Не читается слишком плохо, вы в основном создаете экспрессивные методы-обертки на своих Page Objects, которые позволяют вам заниматься концепциями высокого уровня, а не возиться повсюду с кишками вашей разметки все время. Ваши извлеченные методы теперь делают эту грязную работу, и эта операция с дробовиком больше не является вашей проблемой.

Иными словами, вы инкапсулируете большую часть шумного, путающего DOM-взаимодействующего кода. Я должен сказать, однако, что иногда разумно извлеченные методы в ваших спецификациях достаточны и читаются немного лучше, так как вы можете избежать использования экземпляров Page Object. В любом случае, давайте посмотрим на реализацию:

specs/support/features/pages/missions.rb

То, что вы видите, - это простой объект Ruby - Page Object - это  по сути, очень простые классы. Обычно вы не создаете Page Objects с данными (когда это необходимо, конечно, вы можете), и вы создаете в основном язык через API, который может использовать пользователь или нетехническая сторона в команде. Когда вы думаете об именовании своих методов, я думаю, что это хороший совет задать себе вопрос: как пользователь описал бы поток или предпринятое действие?

Я должен добавить, что без включения Capybara музыка останавливается довольно быстро.

Вы, наверное, задаетесь вопросом, как работают эти пользовательские матчеры:

RSpec генерирует эти пользовательские матчеры на основе предикатных методов на ваших объектах страниц. RSpec преобразует их, удаляя ? и изменения has на have. Бум, матчеры с нуля без особого шума! Немного магии, я дам вам это. Хороший пример волшебства, я бы сказал.

Поскольку мы положили наш объект страницы в spec/support/features/pages/mission.rb, вам также необходимо убедиться, что в spec/rails_helper.rb не закомментировано следующее.

Если вы столкнетесь с NameError с uninitialized constant Pages, вы знаете, что делать.

Если вам интересно, что случилось с методом sign_in_as, я извлек его в модуль в spec/support/sign_in_helper.rb и указал RSpec включить этот модуль. Это не имеет ничего общего с объектами страницы - просто имеет смысл хранить тестовые функции, такие как sign_in , доступным более глобально, чем через объект страницы.

spec/support/sign_in_helper.rb

И вам нужно сообщить RSpec, что вы хотите получить доступ к этому вспомогательному модулю:

spec/spec_helper.rb

В целом, легко видеть, что нам удалось скрыть особенности Capybara - например, поиск элементов, клик на  ссылки и т. д. Теперь мы можем сосредоточиться на функциональности и меньше на фактической структуре разметки, которая теперь инкапсулирована в Page Object - Структура DOM должна быть наименьшей из ваших проблем, когда вы проверяете что-то как высокоуровневое, как фича спеки.

Внимание!

Конфигурации, такие как factory data, относятся к спекам, а не к Page Object. Кроме того, утверждения, вероятно, лучше размещаются вне ваших Page Objects для достижения принципа разделения ответственности.

На эту тему есть две разные точки зрения. Приверженцы размещения утверждений в Page Objects говорят, что это помогает избежать дублирования утверждений. Вы можете обеспечить лучшее сообщение об ошибках и добиться лучшего стиля «Tell, Do not Ask». С другой стороны, защитники assertion-free Page Objects утверждают, что лучше не смешивать ответственности. Предоставление доступа к данным страницы и логике утверждений является двумя отдельными ответственностяни и приводит к раздутым Page Objects при смешивании. Page Object - это доступ к состоянию страниц, а логика утверждения относится к спецификациям.

Разновидности Page Objects

Компоненты представляют собой наименьшие единицы и более сфокусированные, например, объекты форм.

Страницы объединяют все эти компоненты и представляют собой абстракции полной страницы.

Случаи, как вы уже догадались, охватывает весь поток через потенциально несколько разных страниц. Они более высокого уровня. Они фокусируются на потоке, который пользователь генерирует, когда они взаимодействуют с различными страницами. Хорошим примером для этого является поток покупки, который имеет пару шагов.

Когда и почему?

Это хорошая идея применить этот шаблон немного позже в жизненном цикле проекта - когда вы накопили немного сложности в своих фича спеках и когда сможете идентифицировать повторяющиеся шаблоны, такие как структуры DOM, извлеченные методы или другие общие характеристики, которые есть на ваших страницах.

Поэтому вы, вероятно, не должны сразу начинать писать Page Objects. Вы постепенно подходите к этим рефакторингам, когда возрастает сложность и размер ваших приложений/тестов. Дублирования и рефакторинги, которые нуждаются в улучшении через Page Objects, будут легче выявляться с течением времени.

Моя рекомендация - начать с извлечения методов в фича спеках на локальном уровне. Как только они попадут в критическую массу, они будут выглядеть как очевидные кандидаты для дальнейшего извлечения, и большинство из них, вероятно, будут соответствовать профилю для Page Objects. Начните с малого, потому что преждевременная оптимизация оставляет неприятные следы укуса!

Заключительные мысли

Page Object предоставляют вам возможность писать более четкие спецификации, которые лучше читаются и в целом намного более выразительны, потому что они более высокоуровневые. Кроме того, они предлагают хорошую абстракцию для всех, кто любит писать ООП код. Они скрывают специфику DOM, а также позволяют вам иметь приватные методы, которые выполняют грязную работу, не торча в публичном API. Извлеченные методы в ваших спецификациях не предлагают совершенно такой же роскоши. API объектов страницы не должен делиться особенностями Capybara.

Во всех сценариях, когда изменения в дизайне меняются, ваши описания того, как ваше приложение должно работать, не должны меняться при использовании Page Objects - ваши фича спеки более сфокусированы на взаимодействиях на уровне пользователя и не заботятся о специфике реализации DOM. Поскольку изменения неизбежны, Page Objects становятся важными, когда приложения разрабатываются, а также помогают понять, когда размер приложения существенно возрастает.

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.