Тестирование Функциональности Пользователя Сайта С Использованием Объектов Страницы Capybara

Объекты страницы может использоваться как мощный метод абстрагирования (изоляции) ваших тестов от технической реализации.

Важно помнить, что их (Объекты страниц) можно использовать для повышения стабильности тестов и поддержания принципа СУХОЙ (не повторяйтесь) - инкапсулируя функциональность (сайта) простыми методами.



Другими словами

Объект страницы — это экземпляр класса, который абстрагирует (изолирует) пользовательский интерфейс от тестовой среды, представляет методы взаимодействия с пользовательским интерфейсом и извлекает необходимую информацию.



Терминология

Срок Объект страницы слишком общее понятие.

По моему опыту Объект страницы включает следующие 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

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.