Статьи

Тестирование объектов страницы с помощью SitePrism

Призма Спектр Иллюстрация на синем фоне

В этой статье я расскажу о SitePrism , инструменте тестирования, о котором я недавно узнал и которым пользуюсь. Вот описание SitePrism от его создателей:

SitePrism предоставляет вам простой, чистый и семантический DSL для описания вашего сайта с помощью шаблона объектной модели страницы, для использования с Capybara в автоматическом приемочном тестировании.

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

Учебник по объектам страницы

Объекты страницы инкапсулируют детали реализации страницы (в нашем примере это HTML-документ) и предоставляют специальный API, который позволяет вам, тестеру, тестировать элементы на странице. Такая инкапсуляция деталей делает объекты страниц особенно удобными в качестве инструмента тестирования.

Давайте проиллюстрируем это на примере. Здесь у нас есть объект страницы, который наследуется от класса SitePrism::Page :

 class LoginPage < SitePrism::Page element :username_field, "input[name='username']" element :password_field, "input[name='password']" element :flash, "div.flash" def log_in(username, password) username_field.set(username) password_field.set(password) click_on('Log In') end end class ProfilePage < SitePrism::Page element :flash, "div.flash" def flash_message flash.text end end 

Давайте посмотрим, как мы можем использовать наш пример объекта страницы:

 feature 'Login' do let(:login_page) { LoginPage.new } before do login_page.load end scenario 'a successful login' do profile_page = login_page.log_in('admin', 'password') expect(profile_page.flash_message).to eq("Ohai! Welcome Admin.") end end 

Приведенный выше фрагмент кода иллюстрирует, как мы можем использовать объекты страниц SitePrism в наших тестах функций RSpec. Готовы узнать больше?

Внедрение призмы сайта в ваш проект

Установка сайта Prism — дело безболезненное. В вашем Gemfile :

 group :test do # ... gem 'rspec-rails', '~> 3.0.0' gem 'capybara-rails' gem 'site_prism' # ... end 

Обратите внимание, что для примера проекта мы будем использовать RSpec 3. Кроме того, вам понадобится Capybara для использования SitePrism.

Работа с примером проекта

Лучший способ узнать о SitePrism (да и вообще обо всем остальном) — это получить опыт. Для этого я подготовил пример приложения, которое вы можете использовать, чтобы следовать этой статье.

Пример приложения — это интернет-магазин Spree . На данный момент мы используем последнюю ветку 2.3-stable и запускаем ее на Rails 4.1.4.

Чтобы получить проект:

 $ git clone git@github.com:benjamintanweihao/rails_store.git $ cd rails_store $ bundle install 

Задача: тестирование поиска

Чтобы испачкать руки и намочить ноги с помощью SitePrism, мы собираемся протестировать функцию поиска в магазине.

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

Давайте рассмотрим реализацию объекта страницы HomePage . Я храню все свои классы объектов spec/support/pages каталоге spec/support/pages . Вы можете выбирать свои собственные соглашения. Просто убедитесь, что каталог включен в тесты.

Вот как выглядит страница:

home page

SitePrism::Page HomePage находится в подклассе от SitePrism::Page . element используется для указания одного элемента DOM, а elements — для ссылки на коллекцию элементов DOM. Здесь мы передаем символ (например :products ), а затем селектор CSS для нацеливания на различные элементы на странице.

Вот начальная реализация объекта страницы HomePage :

 class HomePage < SitePrism::Page elements :products, "[data-hook='products_list_item']" elements :product_links, "[data-hook='products_list_item'] a" element :search_field, "input#keywords" element :search_dropdown, "select#taxon" end 

Давайте определим метод search_for , который search_for в search_for такие действия, как выбор раскрывающегося search_for , заполнение поля поиска и нажатие кнопки. Мы используем методы Capybara, поэтому, если вы не знакомы с ними, вам обязательно следует обратиться к документации.

 # rails_store/spec/support/pages/home_page.rb class HomePage < SitePrism::Page # elements previously defined def search_for(query, scope='All departments') search_dropdown.select(scope) search_field.set(query) click_on('Search') end end 

Прежде чем мы продолжим, я хочу добавить еще одну строку в код:

 # rails_store/spec/support/pages/home_page.rb class HomePage < SitePrism::Page # elements previously defined def search_for(query, scope='All departments') search_dropdown.select(scope) search_field.set(query) click_on('Search') SearchResults.new # <--------- Added this! ----- end end 

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

Давайте определим страницу результатов поиска:

 class SearchResults < SitePrism::Page elements :products, "[data-hook='products_list_item']" end 

Страница результатов поиска содержит один elements который возвращает коллекцию элементов, которая соответствует селектору "[data-hook='products_list_item']" .

Давайте рассмотрим технические характеристики для более подробной информации:

 # rails_store/spec/features/home/search_products_spec.rb require 'rails_helper' feature 'Product Search' do # factories to load products into the test database include_context 'custom products' let(:home_page) { HomePage.new } before do home_page.load end scenario 'a search term is entered' do search_results = home_page.search_for('jersey') expect(search_results.products.size).to eq(3) end scenario 'search limited by dropdown' do search_results = home_page.search_for('mug', 'Categories') expect(search_results.products.size).to eq(1) end end 

Сначала мы настроили экземпляр HomePage так:

 let(:home_page) { HomePage.new } before do home_page.load end 

Обратите внимание, что мы должны вызвать #load для объекта страницы в другом, чтобы дать сигнал Capybara загрузить страницу в браузере без головы. Далее наш первый сценарий:

 scenario 'a search term is entered' do search_results = home_page.search_for('jersey') expect(search_results.products.size).to eq(3) end 

Он проверяет поисковый термин, введенный в строку поиска. Поскольку он принимает только один аргумент ( jersey ), поле выбора будет установлено на All Departments . Кнопка поиска нажата. Наконец, новый экземпляр SearchResult возвращается.

Вот важный момент. Если следовать потоку пользователей, когда пользователь выполняет поиск, он должен быть направлен на другую страницу. Это представлено экземпляром SearchResult . Поскольку мы указали :products в классе SearchResult , мы можем использовать это в нашем утверждении следующим образом:

 expect(search_results.products.size).to eq(3) 

Учиться больше

Я только поцарапал поверхность того, что может сделать SitePrism. Документация SitePrism хорошо написана. Потратьте 5 минут на чтение этих документов, и я уверен, что вы согласитесь со мной.

Больше практики: тестирование домашней страницы

В репозитории GitHub вы найдете rails_store/spec/features/home/list_products_spec.rb . Посмотрите на методы, используемые объектом страницы, и попробуйте реализовать собственный объект страницы, чтобы тесты прошли.

 scenario 'enters home page' do expect(home_page.product_permalinks).to include('ruby-on-rails-mug', 'ruby-on-rails-tote') end scenario 'clicks on a product' do product_link = home_page.product_links.first product_page = home_page.click_on_product_link(product_link) expect(product_page).to be_displayed expect(product_page.title).not_to be_empty expect(product_page.description).not_to be_empty expect(product_page.price).not_to be_empty end 

Если вы застряли, вы всегда можете посмотреть на реализацию, которую я имею в rails_store/spec/support/pages/home_page.rb .

Последние мысли

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

Еще одна вещь, которая мне нравится в объектах страницы — это инкапсуляция, которую они предоставляют Например, если я решу, что я хочу изменить селектор CSS input#keywords на input#search , мне просто нужно изменить селектор CSS в соответствующем методе element .

Тем не менее, я думаю, что это в основном вопрос личного вкуса. Я с удовольствием использую SitePrism в нескольких проектах и ​​призываю вас хотя бы попробовать.