Successfully reported this slideshow.

QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe

5

Share

Loading in …3
×
1 of 75
1 of 75

QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe

5

Share

Page Objects, вероятно, самый известный на сегодня паттерн, используемый в автоматизации через UI. И самый простой, скажете вы? Не соглашусь, по моим наблюдением применение данного паттерна таит в себе подводные камни даже для наиболее типичных веб-приложений.

В данном докладе я познакомлю вас с тремя простыми и практичными видами PageObject архитектуры - Static, Void и Fluent, продемонстрирую использование кодом, сравню плюсы и минусы подходов. Также я расскажу о важных недостатках Yandex HTMLElements и о некоторых других неудачных подходах, которые повторяются из одного самодельного фреймворка в другой. Вы увидите на примерах, как простой код решает проблемы лучше, чем слишком умный. Примеры на языке Java/Selenide легко переносимы и на другие языки программирования (.NET, Python и другие).

Page Objects, вероятно, самый известный на сегодня паттерн, используемый в автоматизации через UI. И самый простой, скажете вы? Не соглашусь, по моим наблюдением применение данного паттерна таит в себе подводные камни даже для наиболее типичных веб-приложений.

В данном докладе я познакомлю вас с тремя простыми и практичными видами PageObject архитектуры - Static, Void и Fluent, продемонстрирую использование кодом, сравню плюсы и минусы подходов. Также я расскажу о важных недостатках Yandex HTMLElements и о некоторых других неудачных подходах, которые повторяются из одного самодельного фреймворка в другой. Вы увидите на примерах, как простой код решает проблемы лучше, чем слишком умный. Примеры на языке Java/Selenide легко переносимы и на другие языки программирования (.NET, Python и другие).

More Related Content

More from QAFest

Related Books

Free with a 14 day trial from Scribd

See all

QA Fes 2016. Алексей Виноградов. Page Objects: лучше проще, да лучшe

  1. 1. UI Automation:
 Page Objects Лучше проще, да лучше Alexei Vinogradov
  2. 2. Alexei Vinogradov
 IT-Kонсультант
 
 тестирование, управление тестированием, автоматизация в тестировании, коучинг 15+ лет в IT, докладчик SQA Days / Codefest Студент-практикант -> Программист -> Тестировщик ->…
  3. 3. ! !
  4. 4. http://radio-qa.com
  5. 5. Page Objects: идея Разделить код тестов и 
 код нахождения и 
 управления элементами страниц
  6. 6. Page Objects: преимущества Уменьшает дублирование кода Улучшает читаемость и стабильность Уменьшает расходы на поддержку изменений
  7. 7. UI Автоматизация - это скучно
  8. 8. UI Автоматизация 1. Составить тест-кейсы (не все) 2. Сражаться с тулзами 3. Сражаться с изменениями 4. Повторять 1-3
  9. 9. Лекарство Пишем свои фреймворки
  10. 10. Justin Searls
  11. 11. Анти-паттерны в Page Objects: типизированные элементы Yandex HtmlElements testIT WebTester JDI Button Link Image Checkbox
  12. 12. Типизированные элементы Это что за элемент? <a class=„fancy“ href=„javascript:doSmth()“>
  13. 13. Типизированные элементы A это что за элемент? <input type=„button“>
  14. 14. Типизированные элементы A это? :) <div style=„..some-qooxdoo-magic..“>
  15. 15. Проблемы типизирования Проверка валидности в Runtime, не Compile-time
  16. 16. Проблемы типизирования Один элемент - несколько типов
  17. 17. Проблемы типизирования Нужно задумываться о типе элемента Усложняет поддержку, если тип „несовершенен“
  18. 18. Вывод Тотальное типизирование элементов - зло! Но… Поддержка стандартных ситуаций - польза: • Uploads • Select/Dropdown • Tables • …
  19. 19. Static Page Objects (Page Modules) Void Page Objects Fluent Page Objects Реализация
  20. 20. http://selenide.org Selenium inside UI Testing Framework
  21. 21. open(url) open(relativeUrl) Selenide 
 WebDriver driver=new FirefoxDriver();
 driver.get(url);
 
 driver.get(SystemProperties.get(„hostname“)
 + relativeUrl);
  22. 22. $(„cssSelector“) Selenide driver.findElement(By.cssSelector("cssSelector"))
 
 или 
 @FindBy (css="cssSelector")
  23. 23. shouldBe(…), shouldHave(…), should(…) shouldNotBe(…), etc. Selenide Assert + implicit wait + StaleElementReferenceException retry +
 smart logging + screenshot + source code save
  24. 24. Приложение LoginPage HomePage
  25. 25. Static Page Objects Все элементы и методы - static Методы возвращают void или сущности Другое название PageModules* * Яков Крамаренко, „KISS Automation“ (2015)
  26. 26. Static (Page Modules) public class LoginPage {
 
 public static SelenideElement welcomeMsg=$("#welcome"),
 username=$("#username"),
 password=$("#password"),
 loginBtn=$("#login");
 
 public static void login(String user, String pwd){
 username.setValue(user);
 password.setValue(pwd);
 loginBtn.click();
 }
 } 
 public class HomePage { 
 public static SelenideElement welcomeMsg=$("#welcome");
 }
  27. 27. Static (Page Modules) public class LoginPage {
 
 public static SelenideElement welcomeMsg=$("#welcome"),
 username=$("#username"),
 password=$("#password"),
 loginBtn=$("#login");
 
 public static void login(String user, String pwd){
 username.setValue(user);
 password.setValue(pwd);
 loginBtn.click();
 }
 } 
 public class HomePage { 
 public static SelenideElement welcomeMsg=$("#welcome");
 }
  28. 28. Static (Page Modules) public class LoginTest {
 
 @Test
 public void testLogin(){
 open("/");
 LoginPage.welcomeMsg.shouldBe(visible);
 LoginPage.login("admin","12345");
 HomePage.welcomeMsg.shouldBe(visible);
 }
 }

  29. 29. Паттерн public/private (or default) …
 // elements to be used in tests
 public static SelenideElement welcomeMsg = $("#welcome");
 
 // elements to be used in pageObject only
 static SelenideElement username = $("#username"),
 password = $("#password"),
 loginBtn = $("#login");
 …
 
 
 

  30. 30. Антипаттерн Getter/Setter public class LoginPage {
 
 public static SelenideElement welcomeMsg=$("#welcome"),
 username=$("#username"),
 password=$("#password"),
 loginBtn=$("#login");
 
 public static SelenideElement getWelcomeMsg() {
 return welcomeMsg;
 }
 
 public static SelenideElement getUsername() {
 return username;
 }
 
 public static SelenideElement getPassword() {
 return password;
 }
 
 public static SelenideElement getLoginBtn() {
 return loginBtn;
 }
 
 public static void login(String username, String pwd){
 getUsername().setValue(username);
 getPassword().setValue(pwd);
 getLoginBtn().click();
 }
 }

  31. 31. Антипаттерн Getter/Setter Ненужные строчки кода Увеличивает „шум“ в полезном коде
  32. 32. Static imports import static com.app.pages.LoginPage.*;
 
 public class LoginTest {
 
 @Test
 public void testLogin(){
 open("/");
 welcomeMsg.shouldBe(visible);
 login("admin","12345");
 HomePage.welcomeMsg.shouldBe(visible);
 }
 }
 Не всегда хороши:
  33. 33. Static imports import static com.app.pages.FormElement.*; 
 public class FormTest {
 
 @Test
 public void shouldBeInitiallyEmpty(){
 firstname.shouldBe(empty);
 lastname.shouldBe(empty); addressLine1.shouldBe(empty); addressLine2.shouldBe(empty); mobilePhone.shouldBe(empty); }
 }
 Иногда полезны:
  34. 34. Преимущества - недостатки + Очень просто и доступно для начинающих - (очень редко) Проблемы при параллелизации 
 (может зависеть от фреймворка, из-за static) ? меньше гибкости: 
 не рекомендуется хранить состояние 
 нельзя сделать текучий (fluent) интерфейс
  35. 35. Приложение LoginPage HomePage
  36. 36. Void Page Objects Убираем static из описания полей и методов Добавляем конструктор
  37. 37. Void Page Objectspublic class LoginPage {
 
 public SelenideElement welcomeMsg = $("#welcome");
 
 SelenideElement username = $("#username"),
 password = $("#password"),
 loginBtn = $("#login");
 
 public void login(String username, String pwd) {
 …
 }
 
 public LoginPage(){
 welcomeMsg.shouldBe(visible);
 }
 } public class HomePage {
 
 SelenideElement welcomeMsg=$("#welcome");
 
 public SelenideElement loggedInUser=$("#loggedInUser");
 
 public HomePage(){
 welcomeMsg.shouldBe(visible);
 }
 }
  38. 38. Void Page Objects public class LoginTest {
 
 @Test
 public void testLogin(){
 open("/");
 new LoginPage().login("admin","12345");
 HomePage homePage=new HomePage();
 homePage.loggedInUser.shouldHave(text("admin"));
 }
 }
  39. 39. Преимущества - недостатки + Очень просто и доступно для начинающих +/? Проверки в конструкторе +/? можно хранить состояние 
 (пример - выбранная строка таблицы)
  40. 40. Fluent Page Objects Методы возвращают PageObject страницы перехода Если перехода нет - возвращается текущий PageObject
  41. 41. Fluent Page Objects public class LoginPage {
 
 public SelenideElement welcomeMsg = $("#welcome");
 …
 public HomePage login(String username, String pwd) {
 this.username.setValue(username);
 password.setValue(pwd);
 loginBtn.click();
 return new HomePage();
 }
 
 public LoginPage(){
 welcomeMsg.shouldBe(visible);
 }
 }

  42. 42. Приложение HomePage
  43. 43. Fluent Page Objects public class HomePage {
 
 SelenideElement welcomeMsg=$("#welcome"),
 reloadBalanceBtn=$("#reloadBalance"),
 balanceDetailsBtn=$("#balanceDetails");
 
 … }
 
 public HomePage reloadBalance(){
 reloadBalanceBtn.click();
 return this; // return new HomePage();
 }
 
 public BalanceDetailsPage openBalanceDetails(){
 balanceDetailsBtn.click();
 return new BalanceDetailsPage();
 }
 }

  44. 44. Fluent Page Objects public class LoginTest {
 
 @Test
 public void testLogin(){
 open("/");
 HomePage homePage=new LoginPage().login("admin","12345");
 homePage.loggedInUser.shouldHave(text("admin"));
 }
 }
  45. 45. Fluent Page Objects public class FlowTest {
 
 @Test
 public void fluentTest(){
 new LoginPage().login("admin","12345")
 .reloadBalance()
 .openBalanceDetails();
 }
 
 @Test
 public void nonfluentTest(){
 HomePage homePage=new LoginPage().login("admin","12345");
 homePage.reloadBalance();
 BalanceDetailsPage balancePage=homePage.openBalanceDetails();
 }
 }
 Абсолютно неоднозначно, какой из вариантов лучше
  46. 46. Преимущества - недостатки ? переходы между страницами определены в Page Object - анализ тулзами -/? некоторые сложности, если метод возвращает сущности
  47. 47. Приложение LoginPage
  48. 48. Методы на распутье (Void) public class LoginTest {
 
 @Test
 public void testLogin(){
 new LoginPage().login("admin","12345");
 HomePage homePage=new HomePage();
 homePage.loggedInUser.shouldHave(text("admin"));
 }
 
 @Test
 public void testBadLogin(){
 LoginPage loginPage=new LoginPage();
 loginPage.errorMsg.shouldNotBe(visible);
 loginPage.login("admin","admin");
 new LoginPage().errorMsg.shouldBe(visible);
 //loginPage.errorMsg.shouldBe(visible);
 }
 }
  49. 49. Методы на распутье (Fluent) 
 …
 
 public HomePage login(String username, String pwd) {
 doLogin(username, pwd);
 return new HomePage();
 }
 
 public LoginPage badLogin(String username, String pwd) {
 doLogin(username, pwd);
 return new LoginPage(); //return this;
 }
 
 private void doLogin(String username, String pwd) {
 this.username.setValue(username);
 password.setValue(pwd);
 loginBtn.click();
 }
 
 … 
 }
  50. 50. Методы на распутье (Fluent) public class LoginTest {
 
 @Test
 public void testLogin(){
 HomePage homePage=new LoginPage().login("admin","12345");
 homePage.loggedInUser.shouldHave(text("admin"));
 }
 
 @Test
 public void testBadLogin(){
 LoginPage loginPage=new LoginPage().badLogin("admin","admin");
 loginPage.errorMsg.shouldHave(text("Error"));
 }
 }

  51. 51. Немецкая шутка Сколько немцев нужно, чтобы вкрутить лампочку?
  52. 52. Анти-паттерны: наследование Наследование сущностей - О.К.
  53. 53. Анти-паттерны: наследование Наследование страниц - плохо
  54. 54. Анти-паттерны: наследование Усложняет поддержку Лучше пользуйте композицией Или элементами без композиции Или копипейстом…*
  55. 55. S.O.L.I.D. Правила SOLID для тестов - зло! потому что тестовый код ПОСТОЯННО исполняется
  56. 56. Паттерн Page Elements (Page Blocks) сложно или невозможно обозначить страницы блоки элементов повторяются на разных страницах поддержка в Yandex HTMLElements и др. паттерн можно использовать без композиции
  57. 57. Тесты с Page Elements без композиции public class NonCompositeTest {
 
 @Test
 public void elementTest(){
 new LoginPage().login(„admin“,"12345"); HomePage page=new HomePage();
 AddressElement address=new AddressElement();
 page.userName.shouldBe(visible);
 address.zipCode.shouldBe(visible); 
 }
 
 }

  58. 58. Композиция с Page Elements public class HomePage {
 
 … public AddressElement addressElement;
 
 public HomePage(){
 addressElement=new AddressElement(); …
 }
 
 }

  59. 59. Сложности с Page Elements <div id=„address1“> … // code of addressElement … </div> <div id=„address2“> … // code of addressElement … </div> SavingAccountPage VisaAccountPage Посмотрите Yandex HtmlElements Или напишите своё решение Или …
  60. 60. 4 стадии развития 1. Знаю как сделать 2. Знаю как сделать эффективно 3. Знаю как сделать изящно 4. Знаю как не делать
  61. 61. Дублирование кода SavingAccountPage VisaAccountPage public class SavingAccountPage { SelenideElement page=$("#address1"),
 street=page.$(„#street“), city=page.$(„#city“),
 zipCode=page.$(„#zipCode“) …
 } public class VisaAccountPage { SelenideElement page=$("#address2"),
 street=page.$(„#street“), city=page.$(„#city“),
 zipCode=page.$(„#zipCode“) …
 }
  62. 62. Дублирование кода Сopy & Paste безопаснее в Page Object классах,
 чем в прочем коде потому что тестовый код ПОСТОЯННО исполняется
  63. 63. Дублирование кода опасность при рефакторинге когда код Page Object простой - его редко нужно рефакторить
  64. 64. Анти-паттерны: чрезмерное разделение обязанностей Разделение локаторов и методов в разные файлы Выделение констант в properties файлы
  65. 65. Резюме 3 паттерна для написания Page Objects: Вспомогательные паттерны: Static Void Fluent public/private доступ Page Element (Page Blocks) дублирование кода
  66. 66. Резюме анти-паттерны для Page Objects: типизированные объекты наследование getter/setter чрезмерное распределение обязанностей
  67. 67. Резюме темы, не попавшие в доклад Возвращение методами сущностей Паттерн DataTransferObjects Сохранения состояния Простая реализация паттерна композиции
  68. 68. Три простые мысли* В нашем мире не всё, всегда и везде, а кое-что, иногда и местами. Из любых правил есть исключения. И при принятии решений нужно всегда держать голову включенной. * (с) Дорофеев „Вебинар: Джедайская техника доведения дел до конца“
  69. 69. Три простые мысли* Сложность порождает проблемы, а простые вещи зачастую самые действенные. * (с) Дорофеев „Вебинар: Джедайская техника доведения дел до конца“
  70. 70. Три простые мысли* Освоен метод или нет становится понятно, только когда начинаешь его применять. Только через практику можно освоить написание хороших тестов. * (с) Дорофеев „Вебинар: Джедайская техника доведения дел до конца“
  71. 71. Напоследок Всем позитива! Photo: Sekhar, India ©
  72. 72. The End. Questions? skype: alexejv
 email: alexei@vinogradov-it.de twitter: @vinogradoff

×