Всем, доброго времени суток!
Этот топик о том как мы тестируем веб-интерфейс нашего продукта Plus1 WapStart. Мы используем Page Object, т.к. этот паттерн имеет много общего с реальными задачами и позволяет писать автотесты простыми для чтения и понимания.
Что такое Page Object
Page Object — это паттерн для реализации умных автоматических проверок. Gem page-object является имплементацией этого паттерна, который помогает в создании гибких страниц с объектами для тестирования браузерных приложений. Суть в том, чтобы создавать уровни абстракции для отделения тестов от предметов тестирования, и обеспечить простой интерфейс для элементов на странице. Gem работает с watir-webdriver и selenium-webdriver.
Установка Ruby и gems
Установим RVM:
$ bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
Для запуска примеров понадобиться последняя версия Ruby и gems:
$ rvm reload $ rvm install ruby-1.9.3-p125 $ rvm gemset create page-object && rvm use ruby-1.9.3-p125@page-object $ gem install rake page-object
Hello, Page Object!
Создаем RegistrationPage для страницы регистрации — для этого включаем модуль PageObject, указываем адрес страницы и описываем элементы:
class RegistrationPage include PageObject page_url "http://www.passport.wapstart.ru/registration/" text_field(:email, :name => 'mail') text_field(:password, :id => 'hidden-password') select_list(:source, :name => 'informationSource') checkbox(:agreement, :name => 'agreement') button(:register, :name => "register") end
На странице описаны шесть методов, каждый из которых дополнительно сгенерирует еще несколько, об этом далее… Добавляем данные по умолчанию:
DEFAULT_DATA = { 'email' => 'habrahabr@gmail.com', 'password' => 'qwerty', 'source' => 'Прочитал статью, новость о WapStart' }
Создаем метод для заполнения только обязательных полей:
def default(data = {}) data = DEFAULT_DATA.merge(data) self.email = data['email'] self.password = data['password'] self.source = data['source'] check_agreement register end
Все базовые page objects определены, используем их в автотесте. Выберем драйвер selenium-webdriver, передав его в конструктор PageObject:
browser = Selenium::WebDriver.for :ff registration_page = RegistrationPage.new(browser, true) registration_page.default
Аргумент true открывает page_url, если мы попадаем на эту страницу кликом по ссылке, то его можно не передавать. Запустим пример:
$ ruby tests/RegisterDefault.rb
Таким образом в автотестах уходим от использования find_element и локаторов, код легко читаемый и повторно используемый.
Динамическая генерация методов доступа к элементам страницы
Accessors — методы класса, добавленные на страницу, подключением модуля PageObject. Методы генерируют еще один набор методов, которые обеспечивают доступ к элементам веб-страницы:
Пример полностью описанной страницы регистрации:
require 'page-object' require 'selenium/webdriver' class RegistrationPage include PageObject page_url "http://www.passport.wapstart.ru/registration/" DEFAULT_DATA = { 'email' => 'habrahabr@gmail.com', 'password' => 'qwerty', 'source' => 'Прочитал статью, новость о WapStart' } text_field(:email, :name => 'mail') text_field(:password, :id => 'hidden-password') checkbox(:showPassword, :id => 'showPassword') select_list(:source, :name => 'informationSource') text_field(:fio, :name => 'fio') text_field(:phone, :name => 'phone') select_list(:purpose, :name => 'registrationPurpose') checkbox(:haveCode, :id => 'havePartnerCode') text_field(:code, :id => 'plus1PartnerCode') checkbox(:agreement, :name => 'agreement') button(:register, :name => "register") # Exception span(:errorCode, :xpath => "//form[@id='registrationForm']/table/tbody/tr[9]/td[2]/span/span[2]") def default(data = {}) data = DEFAULT_DATA.merge(data) self.email = data['email'] self.password = data['password'] self.source = data['source'] check_agreement register end end
Пример автотеста для проверки валидности партнерского кода:
describe "RegisterUser" do let(:browser) { @browser ||= Selenium::WebDriver.for :ff } #Initialize new instance of Browser(driver) it "InvalidCode" do page = RegistrationPage.new(browser, true) page.email = 'habrahabr@gmail.com' page.password = 'qwerty' page.source = 'Прочитал статью, новость о WapStart' page.check_haveCode page.code = 12345678 page.check_agreement page.register page.errorCode?.should be_true end after { browser.close } end
Примеры доступны на GitHub:
$ git clone git@github.com:ivaravko/pageobject-example.git $ cd pageobject-example/ pageobject-example$ rake
Открытие страницы из другой страницы
В большом проекте много страниц и они связаны между собой, для того чтобы выполнять переход добавим следующий шаг в default метод класса RegistrationPage — LoginPage.new(browser, true). Это позволит перейти на страницу ввода логина и пароля, не изменяя автотест.
def default(data = {}) data = DEFAULT_DATA.merge(data) self.email = data['email'] self.password = data['password'] self.source = data['source'] check_agreement register LoginPage.new(browser, true) end
Автор статьи ivaravko