Чтение документации как средство от граблей и костылей.

se

В этой статье я напишу о различных написанных костылях, найденных лбом граблях и просто интересных вещах, которые на самом деле обозначены в соответствующей документации, но не всегда доходят руки и прочие части тела ее почитать. Часть написанного – мой опыт, что-то услышано от коллег или найдено на просторах коммьюнити тестировщиков. Привожу те, что мне сразу пришли в голову, запомнились особо. Должен заметить, что не все поведение, описанное в документации является очевидным или логичным, именно потому и пишутся различные костыли

securityservПоиск элемента по тексту при помощи CSS. У меня за время использования Selenium скопилась целая библиотека книг, интересных статей и видео о использовании WebDriver и во многих из них, причем достаточно свежих, упоминается CSS локатор в стиле a:contains(‘text’) . То есть люди переписывают этот локатор, даже не проверяя, работает ли он. Но данный локатор не работает! В спецификации W3C можно увидеть пункт с довольно зловещим номером.

666

Особенно мне понравилось недавно просмотренное видео, где хвалили один из новомодных курсов по автоматизации, где радостный участник рассказал, что его научили применению локаторов,  в числе прочего использовать и такой локатор.

securityservБудем честны, хоть раз каждый из нас использовал паузу в стиле Thread.sleep(), а кто не признается, тот и сейчас пользуется 🙂 Как я уже писал – это плохой способ ждать чего-либо и не стоит этим злоупотреблять в своем коде, но если уж решили использовать, то не нужно писать развесистый куст с Thread.sleep() и перехватом InterruptedException. Библиотека WebDriver содержит возможность подождать, впрочем внутри там тот же самый sleep()

new Actions(driver).pause(1000).perform();

— так короче и не бросается в глаза использование слипов.

Стоит отметить, что при написании этой статьи, я обнаружил, что при использовании этого метода в паре со слушателем событий вебдрайвера и хромдрайвером, в глубинах вебдрайвера падает исключение UnsupportedOperation Exception, которое вверх не пробрасывается, но отлавливается упомянутым слушателем. Пауза при этом работает, видимо апи Actions еще не полностью реализовано в хромдрайвере. Но это не мешает использовать паузу.

 

securityservWebElement не хранит свойств элемента страницы. Работая с Java, мы привыкли, что полноценный, сформированный объект хранит в себе свои поля, предоставляет публичные геттеры и не зависит от других объектов. Скажем ArrayList со значениями, полученными откуда угодно, доступен независимо от текущей доступности источника данных. Но WebElement  для запроса тега, текста или других параметров использует запрос к вебдрайверу и если браузер закрыт или изменилась страница, был переход на другой УРЛ, то падает исключение.

Пример:

WebElement element = driver.findElement(By.id(“one”));
driver.get(“http://anotherPage.com”);
System.out.println(element.getText()); // тут падает StaleElementReferenceException так как элемента нет на странице.

Казалось бы, объект element создан и все знает о своем состоянии, но по факту это не так, любые параметры получаются запросом к драйверу. И в коде

if (element.isDisplayed()) {
    System.out.println(element.isDisplayed());
}

будет сделано два запроса и не к элементу, а непосредственно к драйверу браузера, что дольше и может вызывать исключения по указанным выше причинам.

securityservУ вебдрайвера есть АПИ работы с логами браузера, что порой очень удобно – можно после каких-то действий проверить нет ли ошибок в консоли. Но работает это апи довольно неочевидным образом – при запросе логов они удаляются (для запрошенного уровня browser, driver и так далее) и заново их получить (те же самые логи) вы не можете!

То есть допустим два простых метода получения ошибок браузера и проверки наличия таких ошибок

public List consoleErrors() {
        return driver.manage().logs().get("browser").filter(Level.SEVERE);
    }

public boolean isConsoleErrorsExists(){
        return consoleErrors().size() > 0;
}

Если мы воспользуемся методом isConsoleErrorsExists() то даже если ошибки и были, мы их уже не увидим – логов больше нет, мы их запросили внутри метода, вызвав consoleErrors(). Используйте логи сразу при получении, второго шанса не будет!

securityservПри использовании поиска по локатору className будут найдены не только все элементы у которых класс точно равен искомому, но и все те, где искомое лишь один из классов элемента. То есть при поиске By.className(«link») будут найдены и элементы, где class=’link’, и все те, кто содержит link, например class = ‘link b-sethome__link i-bem link_js_inited’. Это нужно учитывать.

securityservИногда нужно проверять какие то ссылки со страницы, или новые урл на предмет доступности, я в свое время накидал простенький код для проверок с использованием средств Java. Но в библиотеке Selenium уже есть очень полезный в подобных случаях класс UrlChecker, позволяющий проверять доступность ссылок, а конкретнее он ждет в течение заданного времени, что УРЛ вернет код ответа 200, означающий доступность страницы. Это можно сделать так

 new UrlChecker().waitUntilAvailable(timeOutInSeconds, TimeUnit.SECONDS, new URL(“http://site.com”));
// останется только обработать TimeOutException

securityservКак то приходилось писать костылек по скроллированию большой интерактивной страницы в самый низ для проверок, но оказалось и тут все написано до нас! Есть очень удобный интерфейс Locatable, который позволяет получить координаты элемента относительно окна, страницы или всего экрана. А самое важное, что для этого происходит автоматически скроллирование к этому элементу, чтобы он стал видимым. Применяется вот так

((Locatable) element).getCoordinates().inViewPort();

Магия происходит именно в методе inViewPort(); согласно спецификации вместо него с тем же эффектом можно вызвать и onScreen() – но он пока не реализован в драйверах, в отличие от inViewPort().

Данной статьей я надеялся мотивировать всех на подробное изучение документации как по Selenium, так и по сопровождающим его библиотекам, чтобы находить нюансы при чтении спеков, а не при написании кода.

И всех с прошедшими праздниками!

 Software-Testing.Ru

Реклама

Отладка Selenium тестов в jshell, не забывая про Idea

java9

Многие уже в курсе, что с Java 9 к нам пришла и джава-консоль jshell, позволяющая быстро выполнять джава-код без лишних телодвижений. Например для извечного «Hello, world!» не нужно создавать класс, а в нем метод main, просто пишем в консоли System.out.println(«Hello, world!»).

Jshell как уже говорилось идет в составе 9 Java, при условии верно прописанных переменных окружения просто пишем в командной строке jshell  и немного ждем, запуск не мгновенный.

По умолчанию в jshell импортировано несколько пакетов, которые можно посмотреть командой /imports, все остальное при необходимости нужно импортировать самим.

imp

Как видим, можно проводить расчеты, работать со стримами и файлами, по-быстрому проверить какой то код не создавая классов и не обрабатывая исключений, к примеру можно вывести содержимое файла не обрабатывая FileNotFoundException

file

Но ближе к делу! Консоль можно использовать для отладки ваших тестов на  Selenium потому что она позволяет:

  • не писать излишнего кода, не создавать классов, не смотреть пока на исключения
  • в случае падения исключения продолжать выполнение, предприняв необходимые действия (изменить урл, локатор  и т.п.) при этом браузер жив и продолжает работать
  • добавлять новые переменные в код
  • в результате вывести весь ваш код командой /list  и скопировать его в ваш тест
  • демонстрировать простые действия или обучать работе с Selenium

Для начала нам нужна сама библиотека Selenium, поэтому качаем свежую версию стендалон-сервера и кладем его в нужную папку, у меня это та же папка где и драйвера браузеров лежат. Потом указываем нашей jshell где искать библиотеку, есть несколько способов сделать это, я указываю при запуске прямо в инструменте Выполнить Windows, так как он запоминает параметр и больше вводить не нужно

jshell —class-path C:\drivers\selenium-server-standalone-3.8.1.jar

path

После этого начинается стандартная работа с драйвером, главное не забывайте импортировать нужные пакеты. Ниже показан запуск хром-браузера(расположение драйвера берется из PATH)

chrome

Пошагово работаем с браузером при этом у нас и браузер доступен, мы можем в его консоли подсмотреть локаторы и прочую информацию, и драйвер доступен — мы можем продолжать выполнять наш сценарий.

Завершив, выводим весь наш сценарий

list

И на сладкое! Еще удобнее работать с jshell в среде разработки Intellij Idea! Просто открываем терминал Идеи, запускаем там jshell с нужными настройками и готово. Тут есть большое удобство в том, что можно тут же код копировать из Идеи в консоль и обратно.

idea

Не забывайте почитать документацию по jshell, там много интересного.

P.S. Я не предлагаю вам отлаживать или писать тесты именно так, скорее продемонстрировал еще одну возможность, которая, на мой взгляд, может быть удобна в определенных ситуациях.


Software-Testing.Ru

 

 

 

 

 

 

 

Ожидания в стиле Java 8

083402_kx1b2e8athumbnail

На мысль навел просмотр видео, в котором Сергей Король справедливо напомнил, что многие из нас «упираются» собственно в средства Селениума и не используют всю силу благословенной Java. Уже вышла 9 версия, а многие еще недостаточно освоили 8, часто ли вы используете в проекте лямбды, стримы, функциональные интерфейсы?

Покажу небольшой пример применения функциональных интерфейсов для ожиданий, который делает код кратким, понятным и, главное, вполне в стиле 8 Java. Идею я честно взял из вышеуказанного видео, немного поправив для своих нужд.

Сначала пишем небольшой enum, в котором используем все наиболее часто применяемые ожидания. Вот весь код, далее обсудим:

import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;

import java.util.function.Function;

public enum WaitConditions {
   visible   (ExpectedConditions::visibilityOfElementLocated),
   exist     (ExpectedConditions::presenceOfAllElementsLocatedBy),
   clickable (ExpectedConditions::elementToBeClickable),
   invisible (ExpectedConditions::invisibilityOfElementLocated);

   WaitConditions(Function<By, ExpectedCondition> type) {
      this.type = type;
   }

   public Function<By, ExpectedCondition> getType() {
      return type;
   }

   private final Function<By, ExpectedCondition> type;
}

Тип нашего enum  это функциональный интерфейс Function, который получает на вход By (наш локатор) и возвращает ExpectedCondition то есть те самые условия ожидания.

 visible (ExpectedConditions::visibilityOfElementLocated),
 exist (ExpectedConditions::presenceOfAllElementsLocatedBy),
 clickable (ExpectedConditions::elementToBeClickable),
 invisible (ExpectedConditions::invisibilityOfElementLocated);

Тут мы собственно перечисляем нужные значения и те методы, на которые их нужно завязать.

private final Function<By, ExpectedCondition> type;

Обратите внимание на ? — это необходимо для использования invisibilityOfElementLocated, так как он в отличие от остальных методов возвращает ExpectedCondition.

С enum разобрались, теперь посмотрим на метод, который будет использовать его. Сразу оговорюсь,  я использую возвращаемое значение boolean, а не кидаю исключение выше, но это мой стиль работы, вы можете модифицировать метод:

public boolean waitFor(By locator, WaitConditions conditions) {
   WebDriverWait wait = new WebDriverWait(driver, defaulTime);
   try {
      wait.until(conditions.getType().apply(locator));
      return true;
   } catch (TimeoutException ex) {
      //делаем скриншот, логируем и  т.д.
      return false;
   }
}

defaultTime — это переменная int, сколько конкретно секунд ждать по умолчанию, при желании ее можно менять, driver это конечно же наш WebDriver. Вот тут все происходит wait.until(conditions.getType().apply(locator)); — наш локатор используется для ожидания соответствующего типа.

Не так много кода мы написали, но все это просто и лаконично позволит нам в коде писать вызовы наших ожиданий в стиле

waitFor(By.id("loginButton"), visible);
или
waitFor(submitButton, clickable);

По-моему достаточно просто использовать и легко читается, даже тому, кто впервые увидит ваши тесты.

Software-Testing.Ru

 

Headless Chrome вместе с Selenium WebDriver — для нетерпеливых

google_now_in_chrome_canary_release_nemmfq

Кто еще не в курсе, начиная с 59 версии в браузер Хром будет введена возможность запуска в headless-режиме, то есть без создания визуального окна браузера. Это позволит прогонять тесты быстрее (теоретически) и с меньшими затратами ресурсов, а главное — позволит запускать тесты на системах без графической составляющей. Не беспокойтесь — возможность делать скриншоты никак не пострадает.

Естественно, кроме самого браузера необходимо дождаться и новой версии chrome driver (текущая 2.29). Но если ждать не хочется, а хочется уже сейчас посмотреть и попробовать, то вот простой рецепт (проверялось для chrome driver 2.29 на Windows 10)

Скачиваем и устанавливаем Chrome Canary, который поддерживает все новые функции будущей версии Хрома. Не беспокойтесь, установка идет в отдельную папку по умолчанию и ваш родной текущий Хром браузер никак не пострадает. Сразу запоминаем или копируем путь установки.

Стандартно указываем путь к нашему драйверу хром

System.setProperty("webdriver.chrome.driver", System.getProperty("user.dir") + "/vendors/chromedriver.exe");

в данном случае, у меня драйвер лежит в папке проекта, в директории vendors.

Далее указываем хром проперти для использования headless режима

ChromeOptions options = new ChromeOptions();
options.setBinary("C:\\Users\\admin\\AppData\\Local\\Google\\Chrome SxS\\Application\\chrome.exe");
options.addArguments("--headless");

в методе setBinary мы указываем путь к расположению нашего Chrome Canary, ну и гвоздем программы устанавливаем аргумент —headless, который говорит сам за себя.

далее, опять же по стандарту, просто создаем объект браузера

driver = new ChromeDriver(options);

Можно запускать!

Единственный момент, который я сразу обнаружил — невидимое окно браузера всего размером 800х600, видно по скриншотам. Кому то может это и не важно, а у нас приложение меняет некоторые элементы в зависимости от размеров окна. Поэтому, нужный размер окна устанавливаем вот так

options.addArguments("window-size=1800x900");

где 1800х900 это размер, нужный вам.

Родные методы driver.manage().window().maximize(); или driver.manage().window().setSize(); тут не сработают, так как chrome driver все еще 2.29  и видимо пока не может использовать эти операции с headless браузером.

Других сбоев пока не заметил, все кликается, текст вводится, скриншоты выполняются без проблем. Так что кому не терпится — можно пробовать и экспериментировать.

Software-Testing.Ru

Не xpath единым, или использование CSS

logo14

Да, я в курсе, что в сети полно блогов и туториалов по использованию CSS, но у них всех есть общая проблема — они стремятся рассказать о всех функциях и вариантах использования и не говорят когда именно использовать именно CSS локаторы. В итоге начинающий не знает за что схватиться и не понимает когда использовать CSS, а когда Xpath.

По своему опыту убежден, что все функции не нужны для постоянной работы в 99% случаев ни в XPATH, ни в CSS. Основные полезные функции xpath я уже описывал, теперь обсудим Css и когда какие локаторы использовать.

  1. Класс. В CSS очень удобно использовать класс элемента (если он уникален), применяя просто знак «.» (точка). Например для элемента с тегом <div idc__dX351« classfbBtn btn-grflat btn font_button« enabledenabled«> можно указать локатор «.fbBtn«. Да, все так просто. Если элементов с таким словом в классе несколько, то можно указать еще один из классов в строке, например «.fbBtn.btn-grflat«. Тут нужно понимать, что все слова, перечисленные через пробел в теге class, это все классы CSS назначенные данному элементу, то есть найти его можно по любому из них, но конечно fbBtn бросается в глаза как явно уникальное слово в потоке остальных.
  2. id в случаях, когда он уникален, что в наше время роскошь, то просто используется запись в стиле #myid. Коротко и просто.
  3. Значения атрибутов. Легко найти элемент по значению его атрибута, если нет уникального класса или id. <input idc__db231_input« classinput__nativeinput« typetext«  placeholderЭл. почта« nameemail« value=»»/>  Как видим, мало что уникально в описании элемента, вполне оправдано использовать атрибут name и его значение. Получаем input[name=’email’]  Согласитесь, достаточно коротко и понятно, квадратные скобки, как и у xpath означают фильтр, если условий несколько то можно использовать запись в стиле  input[name=’email’][placeholder=’Эл. почта] — в данном случае, это тот же элемент.
  4. Поиск по частичному совпадению значения атрибута. А конкретнее, использования аналогов функций СОДЕРЖИТ, НАЧИНАЕТСЯ С, ОКАНЧИВАЕТСЯ НА. Вышеуказанный инпут можно найти и так input[placeholder*=’Эл’], запись «*=» означает СОДЕРЖИТ, аналог contains() в xpath. В данном случае ее можно заменить функцией НАЧИНАЕТСЯ С вот так input[placeholder^=’Эл’], то есть «^=» является аналогом starts-with в xpath. И, наконец, input[placeholder$=’почта’], дает нам выражение «$=» означающее ОКАНЧИВАЕТСЯ НА, не имеющее аналогов в xpath.
  5. Непосредственный наследник и потомок. Для того, чтобы добраться до непосредственного наследника (аналог child в xpath) нужно использовать запись в стиле div>div
    <div idc__da135« classsignInUsingEmailLbl font_title view« enabledenabled«>
              <div classlbl-cnt«>Входdiv>
    Тут, для того чтобы получить div с текстом Вход, можно использовать такую запись div.signInUsingEmailLbl>div  то есть сначала мы находим родителя по его классу (signInUsingEmailLbl), затем его «ребенка» с тегом div.
    <div idc__da135« classsignInUsingEmailLbl font_title view« enabledenabled«>
              <div classlbl-cnt«>Входdiv>

                   <div classex-cnt«>div>

    Чтобы получить потомка любой вложенности (аналог // или descendant в xpath) нужно просто поставить пробел! Чтобы найти элемент с классом «ex-cnt» в примере выше, используем div.signInUsingEmailLbl  div.ex-cnt то есть опять же находим родителя, а потом любого потомка с классом ex-cnt.

    securityservНа мой взгляд — это самые полезные функции  в CSS, которые легко запомнить, короткие в написании и понимании. По поводу скорости CSS по сравнению с Xpath я уже говорил — разница незначительна, но конечно чем короче в написании локатор, тем лучше. Минусом СSS является то, что поиск идет только сверху вниз, то есть мы не можем найти предка, только потомков (вспоминаем в xpath функции ancestor и parent).

Итак, используем CSS если:

  • есть уникальный класс (.fbBtn) или id
  • есть возможность определить элемент по атрибуту или его части (input*=’email’)
  • есть возможность определить элемент более короткой записью чем в xpath

В других случаях, когда нам нужен предок, нужно движение по иерархии вверх (а иногда вверх-вниз!), нужны сложные условия для получения элемента, лучше использовать xpath. Про логику и правила нахождения локаторов в сложных случаях верстки напишу в другой статье.


Software-Testing.Ru

Плагины браузера в помощь тестеру

аа

По просьбам трудящихся, решил написать о тех плагинах, которые использую в своих браузерах для тестирования нашего веб-приложения. Приложение мы проверяем в нескольких браузерах, но основные моменты проверяем в Chrome и Firefox.

Chrome:

  •  Screencastify. Удобный и понятный инструмент для записи видео, позволяет записывать как текущую вкладку так и весь рабочий стол, сохраняет  в приемлемом по размеру формате.

scr

  • Clear Cache. Обновляет вкладку со сбросам кэша (период настраивается), что бывает очень удобно, особенно для приложений, которые хранят много данных в локальном хранилище. То есть чтобы провести тест «с нуля» порой нужно сбросить кэш браузера, а лезть для этого в настройки не хочется.

cach

  • Spell Checker. Как понятно из названия -проверяет правописание на нескольких языках, не так удобен как плагин у Firefox о котором расскажу ниже. В Хроме требуется скопировать нужный текст и вставить в окно плагина для проверки, что не всегда удобно и просто.

spell

  • Quick Language Switcher. Позволяет изменить язык по умолчанию в браузере, что удобно для проверки локалей. Многие приложения, и наше не исключение, определяют язык пользователя по умолчанию и отрисовывают страницу в соответствии с ним. То есть человек из России откроет сайт на языке родных осин, а англичанин на языке Шекспира. Ну а тестеру надо иногда проверять что все это верно работает.

lang

  • What Font и ColorZilla. Плагины для проверки оформления. Первый, как видно по названию, показывает название шрифта при наведении на него. Второй показывает точный цвет любого элемента как в формате RGB так и шестнадцетеричном. Использую редко, но порой бывает, что прямо в требованиях описан конкретный шрифт или цвет.

font

color

Mozilla Firefox

  • Firebug. Отличный плагин, достойно заменяющий панель разработчика, с огромным количеством функций. В принципе аналог панели разработчика в Хроме, но на мой взгляд, в плане анализа элементов верстки гораздо удобнее. http://getfirebug.com/

fire

  • Firepath. Плагин, который работает непосредственно с Firebug и позволяет находить локаторы CSS и Xpath подсвечивая их на странице или в верстке, проверяет синтаксис введенных выражений.

path

measure

add

На этом пожалуй все, я указал только плагины, которыми пользуюсь сам, ваши могут отличаться, дело вкуса. К примеру проверка xpath для хрома в плагине реализована не так удобно, как в ФФ, элементы верстки мне тоже удобнее смотреть в Firebug, но вот другие функции панели разработчика лучше реализованы в Хроме.

Software-Testing.Ru

Польза JavaScript

В своих заметках я уже не раз упоминал о том, что верстка реальных веб-приложений далека от того что обычно демонстрируют в примерах на курсах и в книгах: ни тебе уникальных id, ни нормальных имен классов. Порой не знаешь к чему привязать локатор, чтобы все не упало при следующем запуске.

Как и  упоминал ранее, многие сложные моменты очень хорошо решаются через обращение к программистам с просьбой добавить нормальный локатор или просто с вопросом как проще достучаться до того или иного элемента.

Но если такой возможности нет, или нельзя исправить локатор в этом месте, или слишком долго, то порой очень пригождается javaScript, который не всегда входит в набор наших знаний. По своему опыту скажу, что порой использование JS реально сокращало время теста и его простоту, так как вместо «костыля» и обходных маневров, происходило обращение к нужному элементу или атрибуту напрямую.

Приведу простой пример:

Имеется вот такая форма с расположенным на ней textarea, а мне понадобился текст, который в ней расположен. Но в данном случае текст не находится в верстке, нет атрибута value или text, откуда можно его выдернуть.

textarea

Через методы getText и getAttribute родного Selenium соответственно тоже не подступиться.

Вот тут и понадобился JS, используя встроенный JavaScript Executor, нам нужно написать запрос для получения значения textarea, в данном случае я использовал CSS локатор.

JavascriptExecutor js = (JavascriptExecutor) driver;
result = (String) js.executeScript(«return document.querySelector(‘.dialog__content textarea’).value»);

По нашему локатору ищется элемент, его значение возвращают нам приводя к Стринг, в итоге мы получаем искомый текст.

К чему я это все? Java — это конечно отлично, но и знать JavaScript хотя бы в рамках написания таких запросов, тоже будет не лишним. Кроме того поможет в общении с разработчиками на их языке.

 
Software-Testing.Ru

Ловим неперехваченные исключения

265e2159dccd1134f6793ad56dad2392

Идея для этой заметки родилась как водится в споре, когда в слак-чате один товарищ задал вопрос -как в Java программах перехватить исключение не используя стандартный алгоритм try-catch(-finnaly). Данному товарищу этот вопрос задали на собеседовании и ответить он на него не смог, поэтому поинтересовался. Вариантов было предложено много, но к сожалению правильного ответа товарищ не знал, поэтому все остались в неведении -что именно имели в виду на собеседовании. Однако во всей беседе, мне понравилось упоминание о интерфейсе собственного обработчика необработанных исключений, которым можно подменить родной джавовский. Идея показалась мне интересной и поэкспериментировав, предлагаю свой вариант реализации.

Нам нужно создать свой класс, имплементящий интерфейс-хендлер для неперехваченных исключений.

public class OwnExceptionHandler  implements Thread.UncaughtExceptionHandler{
        
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        //логируем, делаем скриншоты, вызываем какие то действия, выводим трейс 
    }

}

Как вы понимаете — в закомментированном месте выполняем те действия, которые по нашему мнению необходимо предпринять при получении неперехваченного исключения, например логируем его.

Теперь в основном классе нашей программы регистрируем новый хендлер:

OwnExceptionHandler exceptionHandler = new OwnExceptionHandler();
Thread.currentThread().setUncaughtExceptionHandler(exceptionHandler);

И это собственно все!

Когда в программе происходит необработанное исключение, то есть исключение не пойманное в try-catch или если исключение не то которое в данном try-catch перехватывается, то управление переходит к нашему хендлеру, который и предпринимает нужные действия. То есть при правильной обработке исключений, интерефейс не должен отрабатывать никогда.

Подчеркну, что его использование не отменяет грамотной обработки исключений, это скорее вспомогательный инструмент на случай непредвиденных ошибок, которые, я полагаю, хоть раз видел каждый.

Данный способ вполне применим к тестам, но на самом деле там (jUnit, testNG)  есть вшитые и более удобные интерфейсы, позволяющие отловить падение. Но тем не менее, на мой взгляд данный интерфейс небезынтересный и может применяться в коде обычных программ при разработке. В моих экспериментах прекрасно отрабатывались как NullPointer так и StackOverflow ошибки.

 

 
Software-Testing.Ru

Немного о jQuery или «как дождаться окончания Ajax-запросов»

jquery1-960x600

Веб-приложения в последнее время имеют тенденцию становиться все сложнее, умнее, с мощной логикой и работой с данными. В результате очень часто бывает, что для дальнейшей работы со страницей нам надо убедиться, что все Ajax запросы завершены, данные подгружены, все, что мы хотели изображено на странице. Не всегда можно или удобно привязывать ожидания к появлению/исчезновению какого-либо элемента, вот почему очень часто на форумах задают вопрос «как дождаться окончания Ajax-запросов».

Методов решения как всегда много, но уверяю, как всегда самый лучший — просто подойти к разработчикам клиентской стороны и спросить! Это экономит время, нервы и порой решает проблему в одну строку кода. Именно так получилось у меня, так как оказалось, что нужно запросить всего то одну переменную и если она равна 0 то все завершилось. На моем проекте ситуация осложнялась тем, что мы не используем jQuery или любую другую библиотеку, а пишем на чистом, как золото JavaScript.

Если же к разработчикам вы подойти не можете (они далеко, им некогда, приложение не ваше), то есть простой способ определить имеется ли на странице jQuery и затем проверить, что все ее запросы завершились. Если же используется любая другая библиотека, то просто можно действовать по аналогии.

Итак, сначала метод, который определяет используется ли вообще jQuery на странице (слово This  в названии метода, намекает, что нужно сначала самому перейти на нужную страницу,  метод никуда не переходит):

public boolean isJQueryOnThisPage() {
 try {
    return ((JavascriptExecutor) driver).executeScript("return window.jQuery.active")!=null;
 } catch (WebDriverException e) {
    return false;
 }
}

мы просто используем JavascriptExecutor, запрашивая с помощью скрипта наличие функции window.jQuery.active, если нам возвращает null, то JQuery на странице просто нет. Этим методом рекомендуется пользоваться перед вызовом метода ожидания окончания всех запросов.

И, наконец, метод ожидания окончания Ajax-запросов, при использовании jQuery. В некоторых примерах используют таймер, но я предпочитаю подождать, когда запросы реально завершатся, чем видеть тесты, упавшие из-за того, что неверно выставлен таймер. Прикрутить таймер  в принципе недолго.

public void waitForJQueryEnds() {
  while ((Boolean) ((JavascriptExecutor) webDriver).executeScript("return jQuery.active!=0")) {
    //empty body or you can do something while waiting
  }
 }

По аналогии с первым методом, выполняем скрипт, проверяя активность jQuery, как только вернется false  -метод завершит работу. На месте комментариев можно вставить свой какой то код, тот же таймер.

Еще раз подчеркну -этот метод работоспособен только при наличии jQuery, для других библиотек нужно немного поправить скрипт, а метод определения jQuery на странице будет работать всегда.


Software-Testing.Ru

Не так страшен XPATH как его незнание

xpath-logo    Само собой разумеется и во всех книгах проговаривают, что для нахождения элемента лучше всего и быстрее использовать локаторы id и name и, что характерно, основные примеры по использованию локаторов и по работе Selenium показывают именно с ними. Но в реальной жизни часто бывает так, что id элементов формируется динамически, а потому все привязки к нему бесполезны, class может иметь десятки представителей на странице, а name может отсутствовать. Как вы уже догадываетесь в этом случае нужно применять локаторы xpath и css. В данной статье я не собираюсь говорить о каком то превосходстве над css или сравнивать быстродействие, я лишь расскажу почему я использую именно xpath и как это нужно делать. Букв будет много, так как в свое время мне пришлось достаточно порыться в интернет, чтобы получить нужную мне информацию, я выкладываю все самое полезное, в надежде, что кому это поможет в использовании xpath-локаторов. Важно, что у тебя, мой читатель должно быть хоть небольшой представление о  xpath, если его нет, то можешь скачать длинный мануал тут.

Сначала о том, почему новички (и не только) не любят xpath:

  1. Со времен далекой, далекой Галактики, существует миф о том, что xpath во много раз медленнее css, что на данный момент времени не является правдой. Не знаю как обстояло дело раньше, но в наши дни я лично написал несколько тестов с использованием xpath и css и сравнивая их могу сказать, что никакого значительного преимущества нет, а порой даже xpath работает быстрее. Не собираюсь вступать в длительные баталии по поводу скорости, просто разница в несколько миллисекунд нельзя считать значительной, особенно при общей длительности УИ-тестов.
  2. Xpath неверно используют, во многом из-за того, что стандартные панели разработчика и плагины выдергивают xpath из страницы в совершенно непотребном виде, который неудобен и нечитаем. Потому у многих сложилось мнение, что xpath это тяжеловесная и непонятная ерунда.
  3. Нет или по меньшей мере мне не попался какой-нибудь вменяемый мануал по xpath, в основном предлагают ссылки на pdf файл где локаторы приведены всей кучей вместе с css, этакая выжимка, в которой я уверен мало кто разбирается просто из-за обилия информации.

А теперь о том, как обстоят дела на самом деле и в чем преимущества xpath, если его правильно использовать:

— он не уступает (или незначительно уступает) в скорости css

— он понятен и легко читаем, по нему можно понять о каком элементе идет речь

— он похож на язык программирования и его удобно использовать

— можно добраться до самых запрятанных элементов страницы, благодаря выстроенным цепочкам отношений

securityservИтак, несколько правил использования xpath:

  1. Никогда не используй плагины или копирование xpath из кода страницы средствами браузера или веб-разработчика. Вот например как показывает одну ссылку плагин к Файрфокс: //header/div/ul/li[2]/a . Разве из этой ссылки понятно, о каком элементе речь, что мы ищем? Ведь порой бывает, что взглянув на локатор  в коде или в тексте исключения мы должны понять о каком элементе речь. Как это можно понять из такой строки? Я уже не говорю о том, что любой код, основанный на таких локаторах упадет при любом дуновении ветерка. Каждый раз, когда ты пишешь локатор подобный  //div[1]/div[2]/ul/li (продолжать можно долго) в мире умирает что-то хорошее!!! Это, если хотите, говнокод тестировщика, который нужно выжигать каленым железом.
  2. Старайся написать xpath как можно короче и понятнее, используй его возможности и схожесть с языком программирования, чтобы и через месяц ты сам мог понять о каком элементе речь и что нужно поправить в случае изменения верстки
  3. Xpath’у время и место! Если есть возможность использовать id, name или попросить разработчиков внести в код id то сделай это!
  4. Вместо длинной цепочки слешей, как указано выше, используй отношения элементов: предок, потомок, сестринский элемент
  5. Можно и нужно использовать логические операции and, not , or
  6. Нормальный xpath всегда начинается с // и не использует фильтры с номером элемента в стиле [2] (например //div[2])

Переходим к делу и практике, тот xpath, что указан выше (//header/div/ul/li[2]/a)   на самом деле можно указать в виде //a[text()=’Pricing’]. Согласись, что есть разница и в длине текста и в понимании его, ведь тут видно по тегу, что это ссылка и ее текст –Pricing. То есть ты можешь и сам найти этот элемент на странице визуально и в случае исключения с таким локатором сразу знаешь, что и где искать!

Теперь о тех командах, которые тебе реально пригодятся для написания грамотных и удобных локаторов:

  • text() – возвращает текст, содержащийся в элементе. Данную команду незаслуженно забывают и зря, ведь если ты посмотришь на любое веб-приложение, то ты там увидишь кнопки и ссылки, а на кнопках и в ссылках текст. И если id и class у них может меняться, то уверяю, текст на кнопке чаще всего остается тем же, а значит порой правки верстки никак не затрагивают твои локаторы, основанные на тексте! Не стесняйся применять локаторы основанные на тексте! Пример:1

Как видим id явно сгенерирован и привязаться к нему нельзя, класс тоже не внушает доверия, кроме того Selenium не разрешает использовать сложносоставные имена в локаторе className, но тут есть текст, который решает проблему: //a[text()=’Contact us’]

  • contains(параметр, искомое) –возвращает элемент если он содержит искомое, знакомая команда не так ли? Ты ее видишь постоянно в языке программирования. Очень удобно использовать в связке с text() если составляем сложный локатор и не знаем точно всего текста, например: //div[@class=’buttons’ and contains(text(),’Save’)] – как видишь, это некоторый элемент, который относится к кнопкам и на нем есть текст Save. Представь, что в твоем тестируемом веб-приложении есть несколько страниц, на которых есть кнопка сохранения, но с разными текстами –сохранить файл, сохранить диаграмму, сохранить отчет и так далее. Тебе не придется писать локаторы для них всех, хватит одного для всех кнопок сохранения и он описан выше. Обрати внимание на использовании в фильтре сразу двух условий!

Кроме того, очень полезная возможность – это искать элемент по одному из слов в названии класса.Пример:2

Все решается вот так: //div[contains(@class,’intercomBtn’)] , то есть мы ищем элемент, у которого в классе есть какое-то уникальное сочетание слов. Данная возможность contains очень помогает в самых разных ситуациях! Обрати внимание, что параметр и искомое идут через запятую, нельзя писать contains(text()=’smth’)

  • starts-with(параметр, искомое) –все аналогично contains, только эта команда возвращает элементы начинающиеся с искомого. Если возвращаться к примеру с кнопками сохранения, то локатор можно переписать вот так //div[@class=’buttons’ and starts-with(text(),’Save’)] у нас ничего не упадет, так как слово save обычно первое на кнопке и значит локатор опять же будет работать для всех кнопок сохранения. В общем это более узкая форма contains

securityservТеперь пойдут команды отношения элементов (предок, родитель, ребенок, потомок, сестринский элемент), которые позволяют очень гибко найти практически любой элемент на странице при грамотном применении.

Формат использования //начальный элемент/отношение::тег(фильтр) конечного элемента. Обрати внимание на два двоеточия после отношения и не забывай после двоеточий указать тег, а лучше и фильтр искомого элемента, так как потомков может быть и много, а нам нужен какой-то конкретный.

  • sibling – возвращает сестринский элемент, попросту говоря элемент, который расположен на том же уровне что и начальный –не потомок и не предок. Бывают двух типов preceding-sibling -сестринский элемент, который расположен до  (выше) указанного и  following-sibling – сестринский элемент, расположенный после (ниже) указанного. Пример:3

Нам нужно ввести текст в input, но как видишь тут имеется ряд проблем – id динамический, классов и сгенеренных id со словом input на странице много, привязаться вроде не к чему. Но тут есть элемент с текстом, который уникален для страницы, вот к нему и прицепимся:

//div[text()=’Тема’]/preceding-sibling::input   — мы сначала находим уникальный элемент с  текстом, а потом от него ищем предшествующий сестринский элемент, делая фильтр-уточнение, что ищем именно input.  Еще пример:4

Нам нужно кликнуть кнопку, на которой нет текста, только иконка, но как видишь у нее все те же проблемы с id плюс есть куча одноименных классов. Нас спасает то, что у предшествующего элемента есть уникальное название класса, вот от него и будем плясать: //div[contains(@class,’listViewMoreActionsButton’)]/following-sibling::div – находим элемент у которого есть уникальное слово в названии класса и от него уже ищем следующий сестринский элемент, с тегом div. Учитывай, что даже если сестринских последующих элементов  с тегом div будет много вернется только самый первый!

  • parent и child, соответственно родитель и наследник(ребенок), обрати внимание что речь идет о непосредственном прямом родителе или наследнике, а не о предке или потомке. Если возвращаться к примеру 3

То представим, что нам нужен непосредственно элемент с id=__vz4019, для всех на данной картинке  он является родителем (parent) и поэтому его можно вытянуть через любой из них, например //div[text()=’Тема’]/parent::div

securityservКстати, обращение к родительскому элементу, можно заменить двумя точками и без тега, вот так //div[text()=’Тема’]/..

Так как все элементы в примере — дети, то можно любого из них найти от родителя вот так:

//div[contains(@class,’has-floating’)]/child::input – находим родителя, а от него ищем ребенка с тегом input.

  • descendant – потомок, но отличие от child это может быть потомок любой вложенности, так сказать пра-пра-внук в том числе, а не только сын, потому важно не путать с непосредственным наследником! Пример:6

Нам нужна папка именно с определенным именем, но верстка организована так, что сам текст не содержится именно в элементе класса папка, поэтому нам надо найти сначала класс, а потом отфильтровать ту, у которой в потомках есть нужный текст:

//div[@class=’listitem Folder’]/descendant::span[text()=’Folder name’] –сначала находим класс папки, потом среди его потомков ищем  тег span и нужный нам текст. Вы можете спросить –а почему просто по тексту не искать? Дело в том, что элементов с таким текстом на странице может быть больше одного, а нам нужна именно папка.

securityservКстати вместо descendant можно использовать двойной слеш // это означает -любой вложенный элемент. Пример выше превращается в

//div[@class=’listitem Folder’]//span[text()=’Folder name’]

  • ancestor – предок, опять же отличающийся от parent тем, что может быть любой удаленности, то есть прадедушкой. Если возвращаться к предыдущему примеру, то найти элемент папки по тексту можно так //span[text()=’Folder name’]/ancestor:: div[@class=’listitem Folder’]

securityservВажно понимать, что можно, но крайне нежелательно использовать в одном локаторе несколько отношений, например:

//div[@class=’One]/child::div[@class=’Two’]/descendant::input[@class=’Three]. Такой локатор работать будет, но он уже сложно читается и скорее всего есть возможность подобрать другой, не нужно использовать такое без необходимости, помним правило номер 2. Совсем недопустимо использовать в одном локаторе обратные отношения то есть сначала искать потомка, потом его предка или наоборот.

Это все команды и отношения, которые вам пригодятся при написании локаторов! Да, есть еще и другие, вы можете с ними ознакомиться в мануале, прикрепленном в начале статьи, однако я их практически не использовал, а указанных в статье хватает мне и по сей день.

Итак,  применяйте указанные команды, ищите правильные элементы, соблюдайте вышеозначенные правила и у вас не будет проблем с написанием грамотных локаторов, которые легко понять, прочесть, исправить. А главное вы поймете, что xpath очень удобен для написания локаторов к любым элементам.

Software-Testing.Ru