cssSelector和amp;有什么区别? Xpath,哪个更适合跨浏览器测试的性能?

时间:2013-05-28 09:18:47

标签: selenium selenium-webdriver xpath css-selectors webdriver

我正在使用Selenium WebDriver 2.25.0进行多语言Web应用程序&主要测试页面内容(对于不同的语言,如阿拉伯语,英语,俄语等)。

对于我的应用程序,根据性能和性能更好确保它应该支持所有浏览器(即IE 7,8,9,FF,Chrome等)。

提前感谢您提出的有价值的建议。

2 个答案:

答案 0 :(得分:72)

CSS选择器的性能远远优于Xpath,并且在Selenium社区中有很好的文档记录。以下是一些原因,

  • 每个浏览器中的Xpath引擎都不同,因此使它们不一致
  • IE没有本机xpath引擎,因此selenium注入了自己的xpath引擎以实现其API的兼容性。因此,我们失去了使用WebDriver固有推广的本机浏览器功能的优势。
  • Xpath往往变得复杂,因此在我看来很难阅读

但是在某些情况下,您需要使用xpath,例如,搜索父元素或按文本搜索元素(我不建议使用后者)。

您可以阅读Simon here的博客。他还建议使用CSS而不是Xpath。

如果您正在测试内容,请不要使用依赖于元素内容的选择器。这将成为每个地区的维护噩梦。尝试与开发人员交谈,并使用他们用于外化应用程序中文本的技术,如字典或资源包等。以下是我的blog详细解释。

编辑1

感谢@parishodak,这里是link,它提供了证明CSS性能更好的数字

答案 1 :(得分:3)

cssSelector XPath 之间的争论将仍然是 Selenium Community 中最主观的争论之一。到目前为止,我们已经知道的可以总结为:

  • 赞成使用 cssSelector 的人们说它更具可读性和更快性(尤其是在Internet Explorer上运行时)。
  • 尽管那些支持 XPath 的人都宣称它具有横切页面的能力(而 cssSelector 却不能)。
  • 在IE8之类的旧版浏览器中遍历DOM不适用于 cssSelector ,但可以用于 XPath
  • XPath 可以遍历DOM(例如从子级到父级),而 cssSelector 只能遍历DOM(例如从父级到子级)
  • 但是,在旧版浏览器中无法使用 cssSelector 遍历DOM不一定是一件坏事,因为它更多地表明您的页面设计不良,并且可以从一些有用的标记中受益。
  • Ben Burton 提到您应该使用 cssSelector ,因为这是构建应用程序的方式。这使测试更易于编写,讨论和让其他人维护。
  • Adam Goucher 说采用一种更加混合的方法-首先关注ID,然后关注 cssSelector ,仅在需要时使用 XPath 它(例如,沿DOM走),对于高级定位器来说, XPath 总是更强大。

Dave Haeffner test上进行了a page with two HTML data tables,写了一张没有有用属性( ID Class ),另一个与他们一起。我在讨论Why should I ever use cssSelector selectors as opposed to XPath for automated testing?中详细分析了测试程序和该实验的结果。尽管该实验表明每个Locator Strategy在浏览器中都相当等效,但它并不能为我们充分描绘整个画面。在另一个讨论Css Vs. X Path, Under a Microscope中, Dave Haeffner 提到,在端到端测试中,还有许多其他变量在起作用 Sauce startup 浏览器启动,然后等待时间往返于被测试的应用程序。该实验的不幸结果是,一个驱动程序可能比另一个驱动程序更快(例如, IE Firefox ),而实际上并非如此。为了真正了解 cssSelector XPath 之间的性能差异,我们需要更深入地研究。我们通过使用性能基准测试实用程序在本地计算机上运行所有程序来做到这一点。我们还专注于特定的Selenium操作,而不是整个测试运行,并且运行了无数次。我已经在讨论cssSelector vs XPath for selenium中详细分析了具体的测试程序和该实验的结果。但是测试仍然缺少一个方面,即更多的浏览器覆盖范围(例如Internet Explorer 9和10),以及针对更大更深的页面进行测试。

Dave Haeffner 在另一个讨论Css Vs. X Path, Under a Microscope (Part 2)中提到,为了确保以我们需要考虑的最佳方式来涵盖所需的基准,an example that demonstrates a large and deep page


测试设置

为演示此详细示例,已安装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

  • 歌剧

chart-opera


分析结果

  • Chrome和Firefox显然已经过调整,可以提高 cssSelector 的性能。
  • Internet Explorer 8是无法正常工作的 cssSelector 抓包,无法控制的 XPath 遍历大约需要65秒,并且需要38秒的表遍历没有 cssSelector 结果与之进行比较。
  • 在IE 9和10中, XPath 总体上更快。在Safari中,除了使用 XPath 进行一些较慢的遍历之外,其他方面都是一个难题。在几乎所有浏览器中,使用 XPath 完成的the nested sibling traversaltable cell traversal都是昂贵的操作。
  • 这些不足为奇,因为定位器脆弱且效率低下,我们需要避免使用它们。

摘要

  • 总体而言,在两种情况下, XPath 明显比 cssSelector 慢。但是它们很容易避免。
  • 对于非IE浏览器,性能差异略胜于,对于IE浏览器,性能差异略胜于

琐事

您可以使用this library自己执行基准测试,其中 Dave Haeffner 包装了所有代码。