Типичные ошибки начинающих
  писать тесты на WebDriver
         Игорь Хрол
О себе
• Игорь Хрол
• Более шести лет в
  автоматизации тестирования
• Тренер, консультант, инженер,
  менеджер, архитектор
• Selenium, HP QTP, TestCompete,
  Jmeter
• Докладчик на
  SeleniumCamp’2011 и 2012
О чём будем говорить?
Мы все когда-то начинали
  – Подводные камни Selenium’a
  – Ошибки в программировании



Основано на личном
мироощущении
Selenium 2.0 (WebDriver) API
• Selenium – это библиотека для работы с
  браузером
• Требуются знания и усердие, чтобы
  сделать из неё автоматические тесты
Проверки
  //Some actions
  if (isElementPresent(By.id("identifier"))) {
     log("PASS: Element was on the page");
  } else {
     log("FAIL: Element wasn't shown");
  }
  //Some other actions



Только текстовый вывод и ничего
больше…
Проверки
@Test
public void testImportantFeature() {
   //Some actions
   Assert.assertTrue(isElementPresent(By.id("identifier")),
      "Element wasn't shown");
   log("PASS: Element was on the page");
   //Some other actions
}



     Использование готового
     решения
isElementPresent


public boolean isElementPresent(By locator) {
    return driver.findElement(locator).isDisplayed();
}


• NoSuchElementException вместо
  false, если элемента нет на странице
• Возвращает false, если элемент есть на
  странице, но невидимый
isElementPresent
 public boolean isElementPresent(By locator) {
     try {
         driver.findElement(locator);
         return true;
     } catch(NoSuchElementException e) {
         return false;
     }
 }




Если возвращает false, то «подвисает» на
таймаут, указанный в implicitlyWait
isElementPresent
public boolean isElementPresent(By locator) {
   try {
      driver.manage().timeouts().
         implicitlyWait(0, TimeUnit.SECONDS);
      driver.findElement(locator);
      return true;
   } catch(NoSuchElementException e) {
      return false;
   } finally {
      driver.manage().timeouts().
         implicitlyWait(30, TimeUnit.SECONDS);
   }
}


Ненужная исключительная ситуация
isElementPresent
public boolean isElementPresent(By locator) {
   driver.manage().timeouts().
      implicitlyWait(0, TimeUnit.SECONDS);
   boolean result = driver.
      findElements(locator).size() > 0;
   driver.manage().timeouts().
      implicitlyWait(30, TimeUnit.SECONDS);
   return result;
}




Ну и если совсем-совсем хочется…
isElementPresent
public boolean isElementPresent(By locator) {
   driver.manage().timeouts().
      implicitlyWait(0, TimeUnit.SECONDS);
   List<WebElement> list = driver.findElements(locator);
   driver.manage().timeouts().
      implicitlyWait(30, TimeUnit.SECONDS);
   if (list.size() == 0) {
      return false;
   } else {
      return list.get(0).isDisplayed();
   }
}
WebDriver API не возвращает Null
WebElement element =
   driver.findElement(By.id("identifier"));
Assert.assertNotNull(element, "Element wasn't found");

Alert alert = driver.switchTo().alert();
Assert.assertNotNull(alert, "Alert wasn't found");




Ничего не проверяет…
try-catch где попало
public WebElement getElement(By locator) {
   try {
      return driver.findElement(locator);
   } catch (NoSuchElementException e) {
      return null;
   }
}



• Получаете NullPointerException
  вместо NoSuchElementException
• Исключительные ситуации используются
  для «падения» тестов
Сгеренированный XPath
/html/body/div[4]/div/div/div/table
/tbody/tr[2]/td[2]/div/table/tbody/
tr/td[2]/div/a



• Используйте «характерные» свойства
  элементов:
//table[@id=‘dataTable’]
• Выучите XPath
XPath: text() – это функция
Хорошо:
• //a[text()=‘Link’]
• //div[@id=‘container’]
• //table[@name=‘named’]


Плохо:
• //a[@text=‘Link’]
• //a[@text()=‘Link’]
"sleep" для синхронизации




• Не решает проблем синхронизации
• Сильно увеличивает время выполнения
  тестов
implicitlyWait
   driver.manage().timeouts().
      implicitlyWait(30, TimeUnit.SECONDS);


Включайте его, он хороший

• Если вы вызываете метод findElement,
  скорее всего вы хотите его найти
• Если не можем найти, то лучше немного
  подождать
Лишняя логика в скриптах
 public void click(By locator) {
    if (isElementPresent(locator)) {
       driver.findElement(locator).click();
    }
 }




• Тест-скрипты линейные по своей природе
• Чем больше логики в скриптах, тем
  больше шанс допустить ошибку
Собственные циклы для
              синхронизации
public void waitForSomething() {
   int timeout = 30000;
   long start = System.currentTimeMillis();
   while (System.currentTimeMillis() - start < timeout) {
      if (isSomething()) {
         return;
      } else {
         try {
            Thread.sleep(1000);
         } catch (InterruptedException e1) {}
      };
   }
   Assert.assertFalse(true,
      "Timeout is over waiting for something");
}
Собственные циклы для
           синхронизации
public void waitForSomething() {
   WebDriverWait waiter =
            new WebDriverWait(driver, 30, 1000);
   waiter.until(new Predicate<WebDriver>() {
      public boolean apply(WebDriver input) {
         return isSomething(input);
      }
   });
}
XPath vs CSS
“CSS работает быстрее XPath”




• Было актуально только для Selenium RC и
  Internet Explorer
• Уже неактуально
Сравнение скорости на Internet
      Explorer 9.0 + Selenium 2.29.0
               XPath                                  CSS
      //*[@id='g-search-input']                 #g-search-input
                 56                                   45
  //form[@id='globalSearch']//input         form#globalSearch input
                 40                                   30
       //header[@class='g-top']       header.g-top form#globalSearch input
  //form[@id='globalSearch']//input
                 40                                   20

                      Время в миллисекундах

• Да, CSS быстрее
• Но оба метода работают приемлемо быстро
Ошибки в программировании
  Автоматизация тестирования – это
   программирование и разработка
     программного обеспечения
Лучше начать с изучения языка
Названия переменных и методов
int spanNumber =
   driver.findElements(By.tagName("div")).size();
System.out.println("Number of div: " + spanNumber);



public int multiply(int x, int y) {
   return x / y;
}



• Подумайте о ваших последователях
• IDE позволяют эффективно
  переименовывать
Закомментированный код
Система контроля версий хранит все ваши
изменения!
/*public boolean isElementPresent(By locator) {
     driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
     boolean result = driver.findElements(locator).size() > 0;
     driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
     return result;
} */

public boolean isElementPresent(By locator) {
    driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS);
    List<WebElement> list = driver.findElements(locator);
    driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
    if (list.size() > 0) {
         return true;
    } else {
         return list.get(0).isDisplayed();
    }
}
Непонятные комментарии

      private boolean someMethod() {
         // Error
         return false;
      }




Пишите так, чтобы вы сами могли понять
написанное через несколько месяцев
Используйте конвенции языка, на
         котором пишете
• Java:
  – Классы с большой буквы
  – Методы с маленькой буквы
  – Объекты и переменные с маленькой буквы
  – Camel-нотация
• С#
  – Классы с большой буквы
  – Методы с большой буквы
  – Объекты и переменные с маленькой буквы
  – Camel-нотация
warning



Держите код в «чистом» состоянии
Итого
Делать ошибки – это часть развития!
 Давайте учиться программировать
           качественно!
Спасибо за внимание!

Игорь Хрол
• E-mail: khroliz@gmail.com
• Skype: igor.khrol
• LinkedIn: http://www.linkedin.com/in/khroliz
• Блог: http://ru.khroliz.com
• Facebook: https://www.facebook.com/khroliz

Типичные ошибки начинающих писать тесты на WebDriver

  • 1.
    Типичные ошибки начинающих писать тесты на WebDriver Игорь Хрол
  • 2.
    О себе • ИгорьХрол • Более шести лет в автоматизации тестирования • Тренер, консультант, инженер, менеджер, архитектор • Selenium, HP QTP, TestCompete, Jmeter • Докладчик на SeleniumCamp’2011 и 2012
  • 3.
    О чём будемговорить? Мы все когда-то начинали – Подводные камни Selenium’a – Ошибки в программировании Основано на личном мироощущении
  • 4.
    Selenium 2.0 (WebDriver)API • Selenium – это библиотека для работы с браузером • Требуются знания и усердие, чтобы сделать из неё автоматические тесты
  • 5.
    Проверки //Someactions if (isElementPresent(By.id("identifier"))) { log("PASS: Element was on the page"); } else { log("FAIL: Element wasn't shown"); } //Some other actions Только текстовый вывод и ничего больше…
  • 6.
    Проверки @Test public void testImportantFeature(){ //Some actions Assert.assertTrue(isElementPresent(By.id("identifier")), "Element wasn't shown"); log("PASS: Element was on the page"); //Some other actions } Использование готового решения
  • 7.
    isElementPresent public boolean isElementPresent(Bylocator) { return driver.findElement(locator).isDisplayed(); } • NoSuchElementException вместо false, если элемента нет на странице • Возвращает false, если элемент есть на странице, но невидимый
  • 8.
    isElementPresent public booleanisElementPresent(By locator) { try { driver.findElement(locator); return true; } catch(NoSuchElementException e) { return false; } } Если возвращает false, то «подвисает» на таймаут, указанный в implicitlyWait
  • 9.
    isElementPresent public boolean isElementPresent(Bylocator) { try { driver.manage().timeouts(). implicitlyWait(0, TimeUnit.SECONDS); driver.findElement(locator); return true; } catch(NoSuchElementException e) { return false; } finally { driver.manage().timeouts(). implicitlyWait(30, TimeUnit.SECONDS); } } Ненужная исключительная ситуация
  • 10.
    isElementPresent public boolean isElementPresent(Bylocator) { driver.manage().timeouts(). implicitlyWait(0, TimeUnit.SECONDS); boolean result = driver. findElements(locator).size() > 0; driver.manage().timeouts(). implicitlyWait(30, TimeUnit.SECONDS); return result; } Ну и если совсем-совсем хочется…
  • 11.
    isElementPresent public boolean isElementPresent(Bylocator) { driver.manage().timeouts(). implicitlyWait(0, TimeUnit.SECONDS); List<WebElement> list = driver.findElements(locator); driver.manage().timeouts(). implicitlyWait(30, TimeUnit.SECONDS); if (list.size() == 0) { return false; } else { return list.get(0).isDisplayed(); } }
  • 12.
    WebDriver API невозвращает Null WebElement element = driver.findElement(By.id("identifier")); Assert.assertNotNull(element, "Element wasn't found"); Alert alert = driver.switchTo().alert(); Assert.assertNotNull(alert, "Alert wasn't found"); Ничего не проверяет…
  • 13.
    try-catch где попало publicWebElement getElement(By locator) { try { return driver.findElement(locator); } catch (NoSuchElementException e) { return null; } } • Получаете NullPointerException вместо NoSuchElementException • Исключительные ситуации используются для «падения» тестов
  • 14.
    Сгеренированный XPath /html/body/div[4]/div/div/div/table /tbody/tr[2]/td[2]/div/table/tbody/ tr/td[2]/div/a • Используйте«характерные» свойства элементов: //table[@id=‘dataTable’] • Выучите XPath
  • 15.
    XPath: text() –это функция Хорошо: • //a[text()=‘Link’] • //div[@id=‘container’] • //table[@name=‘named’] Плохо: • //a[@text=‘Link’] • //a[@text()=‘Link’]
  • 16.
    "sleep" для синхронизации •Не решает проблем синхронизации • Сильно увеличивает время выполнения тестов
  • 17.
    implicitlyWait driver.manage().timeouts(). implicitlyWait(30, TimeUnit.SECONDS); Включайте его, он хороший • Если вы вызываете метод findElement, скорее всего вы хотите его найти • Если не можем найти, то лучше немного подождать
  • 18.
    Лишняя логика вскриптах public void click(By locator) { if (isElementPresent(locator)) { driver.findElement(locator).click(); } } • Тест-скрипты линейные по своей природе • Чем больше логики в скриптах, тем больше шанс допустить ошибку
  • 19.
    Собственные циклы для синхронизации public void waitForSomething() { int timeout = 30000; long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < timeout) { if (isSomething()) { return; } else { try { Thread.sleep(1000); } catch (InterruptedException e1) {} }; } Assert.assertFalse(true, "Timeout is over waiting for something"); }
  • 20.
    Собственные циклы для синхронизации public void waitForSomething() { WebDriverWait waiter = new WebDriverWait(driver, 30, 1000); waiter.until(new Predicate<WebDriver>() { public boolean apply(WebDriver input) { return isSomething(input); } }); }
  • 21.
    XPath vs CSS “CSSработает быстрее XPath” • Было актуально только для Selenium RC и Internet Explorer • Уже неактуально
  • 22.
    Сравнение скорости наInternet Explorer 9.0 + Selenium 2.29.0 XPath CSS //*[@id='g-search-input'] #g-search-input 56 45 //form[@id='globalSearch']//input form#globalSearch input 40 30 //header[@class='g-top'] header.g-top form#globalSearch input //form[@id='globalSearch']//input 40 20 Время в миллисекундах • Да, CSS быстрее • Но оба метода работают приемлемо быстро
  • 23.
    Ошибки в программировании Автоматизация тестирования – это программирование и разработка программного обеспечения
  • 24.
    Лучше начать сизучения языка
  • 25.
    Названия переменных иметодов int spanNumber = driver.findElements(By.tagName("div")).size(); System.out.println("Number of div: " + spanNumber); public int multiply(int x, int y) { return x / y; } • Подумайте о ваших последователях • IDE позволяют эффективно переименовывать
  • 26.
    Закомментированный код Система контроляверсий хранит все ваши изменения! /*public boolean isElementPresent(By locator) { driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); boolean result = driver.findElements(locator).size() > 0; driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); return result; } */ public boolean isElementPresent(By locator) { driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); List<WebElement> list = driver.findElements(locator); driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); if (list.size() > 0) { return true; } else { return list.get(0).isDisplayed(); } }
  • 27.
    Непонятные комментарии private boolean someMethod() { // Error return false; } Пишите так, чтобы вы сами могли понять написанное через несколько месяцев
  • 28.
    Используйте конвенции языка,на котором пишете • Java: – Классы с большой буквы – Методы с маленькой буквы – Объекты и переменные с маленькой буквы – Camel-нотация • С# – Классы с большой буквы – Методы с большой буквы – Объекты и переменные с маленькой буквы – Camel-нотация
  • 29.
    warning Держите код в«чистом» состоянии
  • 30.
    Итого Делать ошибки –это часть развития! Давайте учиться программировать качественно!
  • 31.
    Спасибо за внимание! ИгорьХрол • E-mail: khroliz@gmail.com • Skype: igor.khrol • LinkedIn: http://www.linkedin.com/in/khroliz • Блог: http://ru.khroliz.com • Facebook: https://www.facebook.com/khroliz