Объекты страницы может использоваться как мощный метод абстрагирования (изоляции) ваших тестов от технической реализации.
Важно помнить, что их (Объекты страниц) можно использовать для повышения стабильности тестов и поддержания принципа СУХОЙ (не повторяйтесь) - инкапсулируя функциональность (сайта) простыми методами.
Другими словами
Объект страницы — это экземпляр класса, который абстрагирует (изолирует) пользовательский интерфейс от тестовой среды, представляет методы взаимодействия с пользовательским интерфейсом и извлекает необходимую информацию.
Терминология
Срок Объект страницы слишком общее понятие.По моему опыту Объект страницы включает следующие 3 типа: Компонентные объекты представляет определенные компоненты или виджеты в пользовательском интерфейсе.
Например: таблицы, меню, статьи и другие блоки, содержащие группу компонентов.
Объект страницы описывает конкретную область или пользовательский интерфейс в веб-приложении.
Он может состоять из нескольких Компонентные объекты и может содержать удобные методы для взаимодействия с абстракцией, содержащейся внутри данного объекта.
Опыт используется для группировки сложного функционала, тестирование которого требует нескольких шагов или взаимодействия с несколькими страницами.
По своему опыту я использовал эту концепцию для абстрагирования сложного поведения на странице (тестирование обучающих страниц, создание нового пользователя и т. д.).
Примеры
Давайте рассмотрим простой тест RSpec Капибара который создает блоги и не использует объекты страниц:Давайте внимательнее посмотрим на код; у него есть несколько проблем.require 'feature_helper' feature 'Blog management', type: :feature do scenario 'Successfully creating a new blog' do visit '/' click_on 'Form Examples' expect(page).
to have_content('Create Blog') fill_in 'blog_title', with: 'My Blog Title' fill_in 'blog_text', with: 'My new blog text' click_on 'Save Blog' expect(page).
to have_selector('.
blog--show') expect(page).
to have_content('My Blog Title') expect(page).
to have_content('My new blog text') end scenario 'Entering no data' do visit '/' click_on 'Form Examples' expect(page).
to have_content('Create Blog') click_on 'Save Blog' expect(page).
to have_content('4 errors stopped this form being submitted') expect(page).
to have_content("Title can't be blank") expect(page).
to have_content("Text can't be blank") expect(page).
to have_content('Title is too short') expect(page).
to have_content('Text is too short') end end
Здесь предусмотрены следующие действия: переход на соответствующую страницу, взаимодействие со страницей и проверка содержимого.
Часть кода дублируется, но это можно исправить, придерживаясь принципа СУХОЙ .
Важно понимать, что этот код сложно поддерживать, если в тестируемом приложении есть изменения.
Например, могут меняться классы элементов, имена и идентификаторы, что требует регулярного обновления тестового кода.
Также в этом коде нет «Семантического контекста», сложно понять, какие строки кода логически сгруппированы.
Введение в объекты страницы
Как обсуждалось в разделе терминологии, Объекты страницы может использоваться для абстракций уровня представления.Взяв предыдущий пример и применив Объект страницы Чтобы создавать новые блоги и просматривать их, мы можем очистить код из предыдущего примера.
Избавившись от конкретной информации о технической реализации, конечный результат (код) должен быть читабельным и не должен содержать специфической информации о пользовательском интерфейсе (id, классы css и т. д.).
require 'feature_helper'
require_relative '.
/pages/new_blog' require_relative '.
/pages/view_blog' feature 'Blog management', type: :feature do let(:new_blog_page) { ::Pages::NewBlog.new } let(:view_blog_page) { ::Pages::ViewBlog.new } before :each do new_blog_page.visit_location end scenario 'Successfully creating a new blog' do new_blog_page.create title: 'My Blog Title', text: 'My new blog text' expect(view_blog_page).
to have_loaded expect(view_blog_page).
to have_blog title: 'My Blog Title', text: 'My new blog text' end scenario 'Entering no data' do new_blog_page.create title: '', text: '' expect(view_blog_page).
to_not have_loaded expect(new_blog_page).
to have_errors "Title can't be blank",
"Text can't be blank",
"Title is too short",
"Text is too short"
end
end
Создание объектов страницы
Первый шаг творения Объекты страницы речь идет о создании структуры базовый класс страницы : module Pages
class NewBlog
include RSpec::Matchers
include Capybara::DSL
# .
end
end
Подключение (питание включено) Капибара :: DSL разрешить экземпляры Объекты страницы использовать методы, доступные в Водосвинка has_css? '.
foo' has_content? 'hello world' find('.
foo').
click
Кроме того, я использовал
включить RSpec::Matchersв приведенных выше примерах использовать библиотеку RSpec ожидание .
Не нарушайте договоренности Объекты страницы не следует включать ожидать .
Однако там, где это уместно, я предпочитаю использовать этот подход, опираясь на встроенные механизмы.
Водосвинка для обработки условий.
Например, следующий код Водосвинка воля ожидать (ожидать) , доступность 'фу' внутри Объекты страницы (в данном случае это себя ): expect(self).
to have_content 'foo'
Однако в следующем коде: expect(page_object.content).
to match 'foo'
Могут возникнуть неожиданные ошибки (может возникнуть плавающий тест), поскольку page_object.content немедленно проверяется на соответствие условию и может быть еще не задекларирован.
Дополнительные примеры я бы рекомендовал прочитать мыслибот написание надежных асинхронных интеграционных тестов с Водосвинка .
Создание методов
Мы можем абстрагировать (описать) местоположение (область), из которого мы хотим получить данные, в рамках одного метода: def visit_location
visit '/blogs/new'
# It can be beneficial to assert something positive about the page
# before progressing with your tests at this point
#
# This can be useful to ensures that the page has loaded successfully, and any
# asynchronous JavaScript has been loaded and retrieved etc.
#
# This is required to avoid potential race conditions.
expect(self).
to have_loaded
end
def has_loaded?
self.has_selector? 'h1', text: 'Create Blog'
end
Важно выбрать семантически правильный имена методов для вашего Объекты страницы
def create(title:, text:)
# .
end
def has_errors?(*errors)
# .
end
def has_error?(error)
# .
end
В целом важно следовать принципу функционально интегрированных методов и, где это возможно, придерживаться принципа единой ответственности.
Компонентные объекты
В нашем примере мы используем класс NewBlog, но реализации для его создания нет. Поскольку мы взаимодействуем с формой, мы могли бы дополнительно ввести класс для представления этого компонента: # .
def create(title:, text:)
blog_form.new.create title: title,
text: text
end
# .
private
def blog_form
::Components::BlogForm
end
Где может быть скрыта реализация методов для BlogForm:
module Components
class BlogForm
include RSpec::Matchers
include Capybara::DSL
def create(title:, text:)
within blog_form do
fill_in 'blog_title', with: title
fill_in 'blog_text', with: text
click_on 'Save Blog'
end
end
private
def blog_form
find('.
blog--new')
end
end
end
Вместе
Используя приведенные выше классы, теперь вы можете запрашивать и создавать экземпляры объектов ( Объекты страницы ) вашей страницы в описании объекта.
require 'feature_helper'
require_relative '.
/pages/new_blog' require_relative '.
/pages/view_blog' feature 'Blog management', type: :feature do let(:new_blog_page) { ::Pages::NewBlog.new } let(:view_blog_page) { ::Pages::ViewBlog.new } # .
end
Примечание.
Я намеренно вручную создал объект страницы в верхней части файла объектов.
В некоторых тестах RSpec может быть удобно автоматически загружать все файлы поддержки и делать их доступными в объектных файлах, но это может привести к чрезмерным накладным расходам при использовании больших фрагментов кода.
В частности, это приведет к медленному запуску и потенциальным непреднамеренным циклическим зависимостям.
Вызов объектов страницы
Теперь в каждом сценарии у нас будет доступ к экземплярам новая_страница_блога И view_blog_page : scenario 'Successfully creating a new blog' do
new_blog_page.create title: 'My Blog Title',
text: 'My new blog text'
expect(view_blog_page).
to have_loaded
expect(view_blog_page).
to have_blog title: 'My Blog Title',
text: 'My new blog text'
end
Соглашения об именах/методы предикатов
Как и в большинстве вещей в Rails/Ruby, существуют соглашения, которые на первый взгляд могут показаться незначительными (невыполнимыми).
В наших тестах мы взаимодействовали с объектом страницы, используя иметь_загружено И иметь_блог : expect(view_blog_page).
to have_loaded expect(view_blog_page).
to have_blog title: 'My Blog Title',
text: 'My new blog text'
Однако имена методов нашего объекта страницы на самом деле has_loaded? И has_blog? : def has_loaded?
# .
end def has_blog?(title:, text:) # .
end
Это тонкая разница, которую необходимо отметить.
Для более подробной информации об этом соглашении я бы рекомендовал прочитать следующую ссылку.
средства сопоставления предикатов .
Git, исходный код, используемый в примерах Оригинал Теги: #tests #Тестирование веб-сервисов #tdd #объект страницы #rspec #capybara
-
Кулон, Шарль Огустен
19 Oct, 24 -
Как Asana Использует Kubernetes
19 Oct, 24 -
Алгоритм Проведения It-Интервью
19 Oct, 24 -
Виджеты Для Интернет-Магазинов
19 Oct, 24 -
Пользовательские Макеты. Часть 2. Celllayout
19 Oct, 24 -
Выпущена Бета-Версия Akavita 5.0 Плюс Форумы
19 Oct, 24