48
atdays.com За пределами PageObject Дмитрий Жарий

За пределами Page Object. ATDays 2013 Киев. Февраль 2013

Embed Size (px)

DESCRIPTION

Более детально в посте: Слайды/Видео к моему докладу на #atdays : За переделами PageObject http://blog.zhariy.com/2013/02/atdays-pageobject.html

Citation preview

Page 1: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com

За пределами

PageObject

Дмитрий Жарий

Page 2: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Давайте познакомимся!

2

Дима Жарий

Page 3: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays 3

Аджендиум… [OK] =================================================

1. Вам не нужен PageObject

2. Вам нужен PageObject

3. PageObject – это паттерн, шаблон… ИДЕЯ!

4. Статический PageObject

5. Динамический PageObject

6. За пределами:

• Паттерн «Цепочка ответственности»

и .Invoke()

• Интерфейс IHaveExpectedControls

• Наследование в тестах

Page 4: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ВАМ ДЕЙСТВИТЕЛЬНО НУЖЕН

PAGE OBJECT?

4

Page 5: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Нет. Если у вас парочка

несложных тестов

5

public void Wikipedia_Smart_Search_Test() { RemoteWebDriver driver = new InternetExplorerDriver(); driver.Navigate() .GoToUrl("http://en.wikipedia.org/wiki/Main_Page"); driver.FindElementByCssSelector(@"div#simpleSearch") .SendKeys("Webdriver Selenium"); Assert.AreEqual("http://en.wiki {...} Driver" , driver.Url); }

Page 6: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Нет. Если у вас несколько

сложных тестов

6

Page 7: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Ведь код можно улучшить

7

Page 8: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Как улучшить?

8

Вынести часто используемый функционал

в общедоступные методы

Отформатировать код

Добавить комментарии driver.FindElement(By.XPath("//a[text()='Log On']")) .Click();

// Click on the Log On link. var logOnLink = driver.FindElement( By.XPath("//a[text()='Log On']")); logOnLink.Click();

Page 9: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

И, если у вас все под

контролем…

9

Page 10: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ВАМ НЕ НУЖЕН PAGE OBJECT!

10

Page 11: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays 11

var ddlMonthSelect = new SelectElement(driver.FindElementByName(@"EXPIRYDATE_MM")); var ddlYearSelect = new SelectElement(driver.FindElementByName(@"EXPIRYDATE_YY")); var txtSecurityCode = driver.FindElementByName(@"CVV"); var btnContinue = driver.FindElementById("btnSubmit"); ddlMonthSelect.SelectByText("05"); ddlYearSelect.SelectByText("15");

Прости, ня!

Page 12: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Когда приходит Хаос…

12

"Тест-простыней" становится слишком много В коде не разобраться без пол-литру

На поддержку уходит уж слишком много времени Легче всё переписать заново

Начинаете ненавидеть разработчиков, которые вынесли div из span

Page 13: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

PageObject – он как книжная

полка

13

Pages

LoginPage

→ Login(name, passwd)

MainPage

→ LogOut()

→ GotoProjects()

→ GotoUserProfile()

→ Search(text)

Page 14: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

PAGE OBJECT – ОН ГИБКИЙ

14

Page 15: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

PageObject – это:

15

Концентрация

на языке задачи,

а не на языке решения

Page 16: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

PageObject – главная цель

16

Обеспечить хранение локаторов в отдельном классе

Обеспечить повторное использование локаторов и/или действий над страницей без дублирования кода

Обеспечить слой абстракции от «драйвера» так, чтобы в тестах не использовались физические элементы идентификации элементов управления приложением

Page 17: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

А выглядит всё вот так

17

MainPage

Create

Account

Page

Т

Е

С

Т

Page 18: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Демо!

18

Page 19: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ЧТО ЭТО БЫЛО? –

СТАТИЧЕСКИЙ PAGE OBJECT!

19

Page 20: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Позитив 01: Тест стал

читабелен

20

public static RemoteWebDriver Driver { get { return WebBrowser.Driver; } }

[TestMethod] public void Donate_test_static() { MyPages.MainPage.Open(); MyPages.MainPage.GoToDonatePage(); MyPages.DonatePage.Donate_50_UAH_Using_Debit_Card(); MyPages.DonationPaymentsForm.FillDonationForm ( firstName : "Vasya", lastName : "Pupkin", securityCode : "555" ); // CUT

}

Page 21: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Позитив 2: Удобная «точка

входа» в страницы

21

Page 22: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Позитив 3: Driver стал доступен

отовсюду!

22

public static class WebBrowser { public static RemoteWebDriver _driver = null; public static RemoteWebDriver Driver { get { _driver = _driver ?? new InternetExplorerDriver(); return _driver; } } }

public static RemoteWebDriver Driver { get { return WebBrowser.Driver; } }

Page 23: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

И еще раз о позитиве

23

Теперь жизнь браузера (драйвера) контролирует класс WebBrowser.

Текущий драйвер доступен из любого участка кода

Любая страница доступна из MyPages.* Наш тест теперь помещается на один экран монитора

Page 24: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Ограничения статического

класса в C#

24

class static class

Наследоваться можно нельзя

Породить много разных можно нельзя

Инициализировать параметрами через конструктор

можно нельзя

Завалить можно полностью нельзя. Очень живучие

Присвоить переменной можно нельзя

Передать как параметр другому методу можно нельзя

Реализовать интерфейс можно нельзя

Использовать статические методы можно можно

Использовать статические поля можно можно

Инициализировать при помощи Webdriver PageFactory

можно нельзя "из коробки", нужно написать свою фабрику

Page 25: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ГИБКОСТЬ – ЭТО ВАЖНО.

PAGE OBJECT КАК OBJECT

25

Page 26: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Тест не изменился! Спасибо,

MyPages

26

Page 27: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Изменения в MyPages

27

public static class MyPages { public static MainPage MainPage { get { return new MainPage();} } public static DonatePage DonatePage { get { return new DonatePage(); } } }

Page 28: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Новая структура проекта

Object Static

28

Page 29: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

AbstractPageBase

29

public abstract class AbstractPageBase { public RemoteWebDriver Driver { get { return WebBrowser.Driver; } } }

Page 30: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

PaymentResultPage

30

public class PaymentResultPage : AbstractPageBase { public void WaitUntilExists() { WebDriverWait wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30)); wait.Until(ExpectedConditions.TitleContains( @"Donate-error - Payments")); } public string GetResultHeaderText() { var lblFirstHeader = Driver. FindElementById(@"firstHeading"); return lblFirstHeader.Text; } }

Page 31: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Changelog

31

Появился базовый класс

AbstractPageBase

Из MyPages.* можно по-прежнему

получить любую страницу Декларация страниц была вынесена из MyPages в отдельные файлы

Мы лишились ограничений статических

классов

ТЕПЕРЬ НАС НЕ ОСТАНОВИТЬ!

Page 32: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Статический/Динамический –

разница в перспективах

32 Статический Динамический

Page 33: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ПАТТЕРНЫ (РЕЦЕПТЫ)

И ИНТЕРФЕЙСЫ (РОЛИ)

33

Page 34: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

ЦЕПОЧКА ОТВЕТСТВЕННОСТИ

/CHAIN OF RESPONSIBILITY/

34

http://bash.im/quote/420885

xxx: тема письма в рабочей почте

" RE: FW: FW: RE: RE: FW: RE: СРОЧНО!!!!!!"

yyy: Вот это проблема структурных

организаций

Page 35: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Chain of Responsibility

35

? ??

???

????

Цепочка ответственности

Page 36: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Iinvokable

36

public interface IInvokable { void Invoke(); bool Exists(); }

Invoke – вызвать

Invokable – то, что можно вызвать

I invokable – Я вызываемый(-оя, -ое)!

Page 37: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

НужнаяPage.Invoke():

37

НужнаяPage.Invoke():

Если я уже Exists() – то вот она я!

Если я не Exists(), то я сделаю:

ПредыдущаяPage.Invoke()

Потом что-то нажму – вот она я!

Donation

Payments

Form

Donate

Page

Page 38: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Что дает нам Iinvokable?

38

Любую страницу можно вызвать с

параметрами по умолчанию

var page = MyPages. PaymentResultErrorInvalidCreditCard; page.Invoke();

Page 39: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Что дает нам Iinvokable?

39

Передать страницу как параметр метода

public void TestThatPageExists(IInvokable page) { page.Invoke(); Assert.IsTrue(page.Exists()); } [TestMethod] public void Test_PaymentResultErrorInvalidCreditCard() { TestThatPageExists( MyPages.PaymentResultErrnvalidCreditCard ); }

Page 40: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Что дает нам Iinvokable?

40

Если нужная страница уже открыта (после

предыдущего теста ) – она будет использована

повторно

public void Invoke() { if (Exists() == false) { var mainPage = MyPages.MainPage; mainPage.Invoke(); mainPage.GoToDonatePage(); } }

Page 41: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

I HAVE EXPECTED CONTROLS

41

Page 42: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Сышишь, а есть какиета

кантролы?

42

public interface IHaveExpectedControls : IInvokable { List<IWebElement> GetExpectedControls(); }

.Invoke()

.Exists()

.GetExpectedControls()

Page 43: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Get Expected Controls

(PageObject)

43

public class DonatePage : AbstractPageBase, IHaveExpectedControls

{ [FindsBy(Using=@"input[name='amount'][value='50']", How = How.CssSelector)]

public IWebElement rbtnDonate50; [FindsBy(Using=@"input[value='Donate by credit/debit card']", How = How.CssSelector)]

public IWebElement btnMakeDonation; public List<IWebElement> GetExpectedControls() { return new List<IWebElement>() { rbtnDonate50, btnMakeDonation }; }

Page 44: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Позволяет писать

универсальные тесты

44

public virtual IHaveExpectedControls CurrentPage { get { return null; } } [TestMethod] public void TestExpectedControls() { CurrentPage.Invoke(); var expectedControls = CurrentPage.GetExpectedControls(); foreach (var expectedControl in expectedControls) { Assert.IsTrue(expectedControl.Displayed); } }

Page 45: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Авто-тесты для авто-тестов?

45

Легкие тесты, которые:

1. Открывают каждую страницу

2. Проверяет каждый важный

элемент страницы

Основной тест-набор

Page 46: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Та да да дам!

46

Page 47: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Спасибы:

47

За то, что доклад состоялся:

Спасибо Вам!

За Invoke() Виктору Линчевскому

Леониду Артемьеву

Помощь в подготовке доклада: Михаил Поляруш

Андрей Ребров

Page 48: За пределами Page Object. ATDays 2013 Киев. Февраль 2013

atdays.com #atdays

Я не прощаюсь, я говорю: до

свидания!

48

Дима Жарий