WapStart corporate blog
February 2012 24

Page Object — путь к совершенным автотестам



Всем, доброго времени суток!
Этот топик о том как мы тестируем веб-интерфейс нашего продукта 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 = {})
   populate_page_with DEFAULT_DATA.merge(data)
   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 = {})
       populate_page_with DEFAULT_DATA.merge(data)
       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 = {})
   populate_page_with DEFAULT_DATA.merge(data)
   check_agreement
   register
   LoginPage.new(browser, true)
end

Автор топика ivaravko

Ссылки

Блог автора гема
Страница на GitHub
Документация

+16
49.7k 56
Comments 8