В этой статье я расскажу о 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
. Вы можете выбирать свои собственные соглашения. Просто убедитесь, что каталог включен в тесты.
Вот как выглядит страница:
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 в нескольких проектах и призываю вас хотя бы попробовать.