Сравниваем скорости поиска элементов

cross

Я уже не раз писал, как и многие до меня, что несмотря на распространенное мнение поиск с помощью XPATH  не медленнее поиска с помощью CSS локаторов. Выдалась свободная минутка и решил потестить немного скорость поиска элемента с помощью разных локаторов и в разных браузерах: Chrome, Firefox, InternetExplorer. Естественно, замеры относительны и воспроизводимы с теми же цифрами только на моей машине, однако есть интересные тенденции.

В Python есть удобная утилита timeit в стандартной библиотеке, к сожалению не смог найти что-то похожее на Java, поэтому просто накидал метод который 100 раз подряд находит элемент по заданному  локатору и выдает среднее затраченное время.

Поиск проводил на странице https://google.ru  и по идее искал я один и тот же элемент, просто задавал различные локаторы для него. Время в миллисекундах.

Браузер

XPATH

CSS

ID

CLASS

NAME

‘//form[@class=’tsf’]’

‘form.tsf’

‘tsf’

‘tsf’

‘f’

Chrome 6-7 6-7 7 6 6-7
Firefox 3-5 4-5 3-5 3-4 3-4
IE 50 (!) 78(!!) 77-80 77-79 76-79

Я конечно знал, что Chrome быстрый, в последнее время я работаю только с ним, но не ожидал, что Internet Explorer будет настолько медленнее, искренне сочувствую тем, кому приходится тестировать УИ на нем!

Второй неожиданностью стало то, что Firefox пусть и немного, но побыстрее Chrome.

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

Естественно, замеры я проводил не один раз и в разном порядке, как 1  локатор за сессию, так и все подряд.

Не успокоившись на этом, запустил консоль Python, который сейчас активно осваиваю, и воспользовался утилитой timeit, которая выдает среднее время за указанное количество повторов функции. Локаторы и сайт естественно остались теми же. Цифры были уже другие, но закономерности сохранились, а именно: Firefox немного быстрее Chrome, Internet Explorer на порядок медленнее обоих браузеров, но при этом поиск по XPATH у него работает гораздо бодрее всех остальных.

Итак, выводы:

1) поиск по XPATH не быстрее CSS, а для браузера Internet Explorer даже наоборот, есть смысл все локаторы писать только на XPATH!

2) Chrome не самый быстрый браузер, пусть и совсем чуть-чуть, но Firefox ищет побыстрее, видимо обновления пошли на пользу Лисе

3) Internet Explorer must die!

4) поиск по id или class имеет только преимущество в удобстве написания локатора, если есть уникальные id или имя класса. Вопреки некоторым встреченным в интернете рассказам, поиск по id или class не быстрее остальных видов поиска

Вот тут пожно почитать про xpath, а вот тут про css!

Software-Testing.Ru

Реклама

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

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

Не 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