Подтвердить что ты не робот

В чем разница между cssSelector и Xpath и что лучше в отношении производительности для кросс-браузерного тестирования?

Я работаю с Selenium WebDriver 2.25.0 на многоязычном веб-приложении и в основном тестирую содержимое страницы (для разных языков, таких как арабский, английский, русский и т.д.).

Для моего приложения, которое лучше соответствует производительности и убедитесь, что оно должно поддерживаться для всех браузеров (то есть IE 7,8,9, FF, Chrome и т.д.).

Заранее благодарим за полезные предложения.

4b9b3361

Ответ 1

Селекторы CSS работают намного лучше, чем Xpath, и это хорошо задокументировано в сообществе Selenium. Вот несколько причин,

  • Движки Xpath различны в каждом браузере, поэтому они несовместимы
  • В IE нет встроенного механизма xpath, поэтому selenium добавляет свой собственный механизм xpath для совместимости своего API. Следовательно, мы теряем преимущество использования встроенных функций браузера, которые по своей природе поддерживает WebDriver.
  • Xpath имеют тенденцию становиться сложными и, следовательно, затрудняют чтение, на мой взгляд.

Однако в некоторых ситуациях вам нужно использовать xpath, например, для поиска родительского элемента или поиска элемента по его тексту (я бы не рекомендовал позже).

Вы можете прочитать блог Саймона здесь. Он также рекомендует CSS поверх Xpath.

Если вы тестируете контент, не используйте селекторы, которые зависят от содержимого элементов. Это будет кошмар обслуживания для каждого региона. Попробуйте пообщаться с разработчиками и использовать методы, которые они использовали для экстернализации текста в приложении, например словари, пакеты ресурсов и т.д. Вот мой блог, в котором это подробно объясняется.

изменить 1

Благодаря @parishodak, вот ссылка, которая предоставляет цифры, доказывающие, что производительность CSS лучше

Ответ 2

Я собираюсь придерживаться непопулярного мнения о селеновом теге SO о том, что XPath предпочтительнее CSS в долгосрочной перспективе.

Этот длинный пост состоит из двух разделов. Сначала я добавлю доказательство того, что разница в производительности между ними составляет 0,1–0,3 миллисекунды (да; эти 100 микро секунд), а затем я поделюсь своим мнением, почему XPath более мощный.


Разница в производительности

Давайте сначала займемся "слоном в комнате" - этот путь медленнее, чем CSS.

С текущей мощью процессора (читай: все, что x86 выпускает с 2013 года), даже на виртуальных машинах browsertack/saucelabs/aws и развитием браузеров (читай: все популярные за последние 5 лет), что вряд ли так. Разработаны браузерные движки, поддержка xpath единообразна, IE находится вне поля зрения (надеюсь, для большинства из нас). Это сравнение в другом ответе цитируется повсеместно, но оно очень контекстуально - сколько из них работает - или заботится о - автоматизации против IE8?

Если есть разница, она составляет доли миллисекунды.

Тем не менее, большинство высокоуровневых инфраструктур в любом случае добавляют не менее 1 мс накладных расходов по сравнению с необработанным вызовом selenium (оболочки, обработчики, хранение состояний и т.д.); Мой личный выбор - RobotFramework - добавляет не менее 2 мсек, которыми я более чем рад пожертвовать ради того, что он предоставляет. Обход по сети от концентратора AWS us-east-1 к концентратору BrowserStack обычно составляет 11 миллисекунд.

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


Измерения

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

Цель - целевая страница BrowserStack и ее кнопка "Зарегистрироваться"; Снимок экрана HTML, на котором написано это сообщение:

enter image description here

Вот тестовый код (python):

from selenium import webdriver
import timeit


if __name__ == '__main__':

    xpath_locator = '//div[@class="button-section col-xs-12 row"]'
    css_locator = 'div.button-section.col-xs-12.row'

    repetitions = 1000

    driver = webdriver.Chrome()
    driver.get('https://www.browserstack.com/')

    css_time = timeit.timeit("driver.find_element_by_css_selector(css_locator)", 
                             number=repetitions, globals=globals())
    xpath_time = timeit.timeit('driver.find_element_by_xpath(xpath_locator)', 
                             number=repetitions, globals=globals())

    driver.quit()

    print("css total time {} repeats: {:.2f}s, per find: {:.2f}ms".
          format(repetitions, css_time, (css_time/repetitions)*1000))
    print("xpath total time for {} repeats: {:.2f}s, per find: {:.2f}ms".
          format(repetitions, xpath_time, (xpath_time/repetitions)*1000))

Для тех, кто не знаком с Python - он открывает страницу и находит элемент - сначала с помощью локатора css, затем с xpath; операция поиска повторяется 1000 раз. Выходными данными являются общее время в секундах для 1000 повторений и среднее время для одной находки в миллисекундах.

Локаторы:

  • для xpath - "элемент div, имеющий точное значение класса где-то в DOM";
  • css похож - "элемент div с этим классом где-то в DOM".

Сознательно выбран, чтобы не быть слишком настроенным; Кроме того, селектор класса цитируется для css как "второй по быстродействию после идентификатора".

Среда - Chrome v66.0.3359.139, chromedriver v2.38, процессор: ULV Core M-5Y10, обычно работающий на частоте 1,5 ГГц (да, "текстовый", даже не обычный i7-зверь).

Вот вывод:

css total time 1000 repeats: 8.84s, per find: 8.84ms

xpath total time for 1000 repeats: 8.52s, per find: 8.52ms

Очевидно, что время нахождения довольно близко; разница составляет 0,32 миллисекунды. Не прыгайте "Xpath быстрее" - иногда это так, иногда это CSS.


Давайте попробуем использовать другой набор локаторов, чуть более сложный - атрибут, имеющий подстроку (по крайней мере, для меня это общий подход, переходящий к классу элементов, когда его часть имеет функциональное значение):

xpath_locator = '//div[contains(@class, "button-section")]'
css_locator = 'div[class~=button-section]'

Два локатора снова семантически совпадают - "найдите элемент div, имеющий в своем атрибуте класса эту подстроку".
Вот результаты:

css total time 1000 repeats: 8.60s, per find: 8.60ms

xpath total time for 1000 repeats: 8.75s, per find: 8.75ms

Разница 0,15 мс.


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

Они делают несколько вещей в коде - щелкают по столбцу для сортировки по нему, затем получают значения и проверяют правильность сортировки пользовательского интерфейса.
Я урежу это - просто получите локаторы, в конце концов - это корневой тест, верно?

Тот же код, что и выше, с этими изменениями в:

  • URL теперь http://the-internet.herokuapp.com/tables; Есть 2 теста.

  • Локаторы для первого - "Поиск элементов по идентификатору и классу" -:

css_locator = '#table2 tbody .dues'
xpath_locator = "//table[@id='table2']//tr/td[contains(@class,'dues')]"

А вот и результат:

css total time 1000 repeats: 8.24s, per find: 8.24ms

xpath total time for 1000 repeats: 8.45s, per find: 8.45ms

Разница 0,2 миллисекунд.

"Поиск элементов путем обхода":

css_locator = '#table1 tbody tr td:nth-of-type(4)'
xpath_locator = "//table[@id='table1']//tr/td[4]"

Результат:

css total time 1000 repeats: 9.29s, per find: 9.29ms

xpath total time for 1000 repeats: 8.79s, per find: 8.79ms

На этот раз это 0,5 мс (наоборот, xpath здесь оказался "быстрее").

Таким образом, через 5 лет (улучшенные движки браузеров) и сосредоточив внимание только на производительности локаторов (никаких действий, таких как сортировка в пользовательском интерфейсе и т.д.), Тот же тестовый стенд - между CSS и XPath практически нет различий.


Итак, из xpath и css, какой из двух вариантов выбрать для производительности? Ответ прост - выберите поиск по идентификатору.

Короче говоря, если идентификатор элемента уникален (как он должен соответствовать спецификациям), его значение играет важную роль во внутреннем представлении DOM в браузере и, следовательно, обычно является самым быстрым.

Тем не менее, уникальные и постоянные (например, не сгенерированные автоматически) идентификаторы не всегда доступны, что приводит нас к "почему XPath, если есть CSS?"


Преимущество XPath

Почему производительность xpath лучше? Просто - универсальность и мощь.

Xpath - это язык, разработанный для работы с документами XML; как таковой, он допускает гораздо более мощные конструкции, чем CSS.
Например, навигация в каждом направлении в дереве - найдите элемент, затем перейдите к его деду и найдите его потомок, обладающий определенными свойствами.
Это позволяет встроенные логические условия - cond1 and not(cond2 or not(cond3 and cond4)); встроенные селекторы - "найдите div, имеющий этих потомков с этими атрибутами, а затем перемещайтесь в соответствии с ним".
XPath позволяет осуществлять поиск по значению узла (его тексту) - как бы не критиковалась эта практика, он очень полезен, особенно в плохо структурированных документах (нет определенных атрибутов, на которые можно переходить, таких как динамические идентификаторы и классы), чтобы найти элемент по его тексту содержание).

Переход в css определенно проще - можно начать писать селекторы за считанные минуты; но через пару дней использования xpath по мощности и возможностям быстро преодолевает css.
И чисто субъективно - сложный css гораздо сложнее читать, чем сложное выражение xpath.

Outro;)

Наконец, опять же очень субъективно - какой выбрать?

ИМХО, нет правильного или неправильного выбора - это разные решения одной и той же проблемы, и нужно выбирать то, что больше подходит для работы.

Будучи "фанатом" XPath, я не стесняюсь использовать в своих проектах сочетание обоих - черт возьми, иногда гораздо быстрее просто скинуть CSS, если я знаю, что он отлично подойдет.

Ответ 3

Спор между cssSelector и XPath останется одним из самых субъективных в сообществе Selenium. То, что мы уже знаем, можно обобщить так:

  • Люди в пользу cssSelector говорят, что он более читабелен и быстрее (особенно при работе с Internet Explorer).
  • В то время как те, кто выступает за XPath, говорят о возможности переворачивания страницы (тогда как cssSelector не может).
  • Обход DOM в старых браузерах, таких как IE8, не работает с cssSelector, но подходит для XPath.
  • XPath может проходить вверх по DOM (например, от дочернего элемента к родительскому), тогда как cssSelector может проходить только по DOM (например, от родительского к дочернему элементу)
  • Однако отсутствие возможности обхода DOM с помощью cssSelector в старых браузерах не обязательно является плохой вещью, поскольку это скорее показатель того, что ваша страница имеет плохой дизайн и может извлечь пользу из некоторой полезной разметки.
  • Бен Бертон упоминает, что вы должны использовать cssSelector, потому что именно так создаются приложения. Это облегчает написание тестов, их обсуждение и помощь других.
  • Адам Гоше говорит, что следует использовать более гибридный подход - сначала сосредоточиться на идентификаторах, а затем на cssSelector и использовать XPath только тогда, когда вам это нужно (например, ходить по DOM), и что XPath всегда будет более мощным для продвинутых локаторов.

Дэйв Хаффнер провел тест на странице с двумя таблицами данных HTML, одна таблица написана без полезных атрибутов (ID и Class), а другая - с ними. Я подробно проанализировал процедуру тестирования и результаты этого эксперимента в обсуждении Почему я должен когда-либо использовать селекторы cssSelector, а не XPath для автоматического тестирования?. Хотя этот эксперимент продемонстрировал, что каждая стратегия локатора является разумно эквивалентной для всех браузеров, она не показала нам адекватной картины в целом. Дейв Хаффнер в другой дискуссии Css Vs. X Path, под упомянутым микроскопом, в сквозном тесте было много других переменных при запуске Play Sauce, запуске Browser и задержке в тестируемом приложении и из него. Неудачный вывод из этого эксперимента может заключаться в том, что один драйвер может быть быстрее другого (например, IE против Firefox), хотя на самом деле это совсем не так. Чтобы получить реальное представление о том, какова разница в производительности между cssSelector и XPath, нам нужно было углубиться. Мы сделали это, запустив все с локальной машины, используя утилиту для сравнения производительности. Мы также сфокусировались на конкретном действии Selenium, а не на всем тестовом прогоне, и выполняли его много раз. Я подробно проанализировал конкретную процедуру тестирования и результаты этого эксперимента в обсуждении cssSelector против XPath для селена. Но в тестах по-прежнему отсутствовал один аспект, то есть больший охват браузером (например, Internet Explorer 9 и 10) и тестирование на более крупной и глубокой странице.

Дейв Хаффнер в другом обсуждении Css Vs. X Path, под микроскопом (часть 2), упоминает, чтобы убедиться, что требуемые тесты покрыты наилучшим образом, нам нужно рассмотреть пример, демонстрирующий большую и глубокую страницу.


Тестовый набор

Чтобы продемонстрировать этот подробный пример, была установлена виртуальная машина Windows XP и Ruby (1.9.3). Также были установлены все доступные браузеры и их эквивалентные драйверы для Selenium. Для тестирования использовалась стандартная библиотека Ruby benchmark.


Тестовый код

require_relative 'base'
require 'benchmark'

class LargeDOM < Base

  LOCATORS = {
    nested_sibling_traversal: {
      css: "div#siblings > div:nth-of-type(1) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3) > div:nth-of-type(3)",
      xpath: "//div[@id='siblings']/div[1]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]/div[3]"
    },
    nested_sibling_traversal_by_class: {
      css: "div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1 > div.item-1",
      xpath: "//div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]/div[contains(@class, 'item-1')]"
    },
    table_header_id_and_class: {
      css: "table#large-table thead .column-50",
      xpath: "//table[@id='large-table']//thead//*[@class='column-50']"
    },
    table_header_id_class_and_direct_desc: {
      css: "table#large-table > thead .column-50",
      xpath: "//table[@id='large-table']/thead//*[@class='column-50']"
    },
    table_header_traversing: {
      css: "table#large-table thead tr th:nth-of-type(50)",
      xpath: "//table[@id='large-table']//thead//tr//th[50]"
    },
    table_header_traversing_and_direct_desc: {
      css: "table#large-table > thead > tr > th:nth-of-type(50)",
      xpath: "//table[@id='large-table']/thead/tr/th[50]"
    },
    table_cell_id_and_class: {
      css: "table#large-table tbody .column-50",
      xpath: "//table[@id='large-table']//tbody//*[@class='column-50']"
    },
    table_cell_id_class_and_direct_desc: {
      css: "table#large-table > tbody .column-50",
      xpath: "//table[@id='large-table']/tbody//*[@class='column-50']"
    },
    table_cell_traversing: {
      css: "table#large-table tbody tr td:nth-of-type(50)",
      xpath: "//table[@id='large-table']//tbody//tr//td[50]"
    },
    table_cell_traversing_and_direct_desc: {
      css: "table#large-table > tbody > tr > td:nth-of-type(50)",
      xpath: "//table[@id='large-table']/tbody/tr/td[50]"
    }
  }

  attr_reader :driver

  def initialize(driver)
    @driver = driver
    visit '/large'
    is_displayed?(id: 'siblings')
    super
  end

  # The benchmarking approach was borrowed from
  # http://rubylearning.com/blog/2013/06/19/how-do-i-benchmark-ruby-code/
  def benchmark
    Benchmark.bmbm(27) do |bm|
      LOCATORS.each do |example, data|
    data.each do |strategy, locator|
      bm.report(example.to_s + " using " + strategy.to_s) do
        begin
          ENV['iterations'].to_i.times do |count|
         find(strategy => locator)
          end
        rescue Selenium::WebDriver::Error::NoSuchElementError => error
          puts "( 0.0 )"
        end
      end
    end
      end
    end
  end

end

Результаты

ПРИМЕЧАНИЕ: выходные данные приведены в секундах, а результаты - для общего времени выполнения 100 выполнений.

В форме таблицы:

css_xpath_under_microscopev2

В форме диаграммы:

  • Chrome:

chart-chrome

  • Firefox:

chart-firefox

  • Internet Explorer 8:

chart-ie8

  • Internet Explorer 9:

chart-ie9

  • Internet Explorer 10:

chart-ie10

  • Opera:

chart-opera


Анализ результатов

  • Chrome и Firefox явно настроены для более быстрой работы cssSelector.
  • Internet Explorer 8 - это пакет cssSelector, который не работает, неконтролируемый обход XPath, который занимает ~ 65 секунд, и 38-секундный обход таблицы без результата cssSelector для сравнения.
  • В IE 9 и 10 XPath быстрее в целом. В Safari это бросок, за исключением нескольких более медленных обходов с XPath. Практически во всех браузерах обход вложенных элементов и ячейки таблицы, выполняемые с XPath, являются дорогостоящей операцией.
  • Это не должно вызывать удивления, поскольку локаторы хрупкие и неэффективные, и мы должны их избегать.

Резюме

  • В целом, есть два обстоятельства, когда XPath заметно медленнее, чем cssSelector. Но их легко избежать.
  • Разница в производительности немного в пользу для браузеров не-IE и немного в пользу для браузеров IE.

Общая

Вы можете выполнить тестирование самостоятельно, используя эту библиотеку, где Дейв Хаффнер свернул весь код.

Ответ 4

В прошлом месяце я собрал данные из более чем 25 различных селекторов в 4 разных браузерах, и я могу сказать, что в целом селекторы Css работают лучше, чем XPath.

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

На основании этого я обнаружил, что:

Селекторы Css лучше работают на Chrome, Edge и Firefox. XPath лучше работают в Internet Explorer.

Давайте посмотрим на определение каждого из них.

Css Selector: строковые шаблоны, которые используют комбинацию тегов HTML, идентификаторов, классов и атрибутов для поиска заданного элемента. Все браузеры имеют одинаковую реализацию Css Selector. Производительность в целом лучше.

XPath: позволяет пользователю перемещаться по структуре HTML/XML веб-страницы. Предоставляет пользователю большую гибкость - может использоваться для выбора родительских/родственных элементов. Каждый браузер имеет собственную реализацию XPath. Это удобнее в использовании, есть вещи, которые вы можете достичь только с помощью XPath.

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

Край

Firefox

Chrome

Internet Explorer

Все вместе

Ответ 5

Основное преимущество использования CSS в IE (как правило, в большинстве браузеров) заключается в том, что оно немного быстрее, чем xpath. Вы можете проверить эту ссылку, чтобы получить лучшее изображение.