Jaka jest różnica między cssSelector i Xpath i która jest lepsza pod względem wydajności do testowania w różnych przeglądarkach?

88

Pracuję z Selenium WebDriver 2.25.0 nad wielojęzyczną aplikacją internetową i głównie testuję zawartość strony (dla różnych języków, takich jak arabski, angielski, rosyjski itp.).

Dla mojej aplikacji, która jest lepsza pod względem wydajności i upewnij się, że powinna obsługiwać wszystkie przeglądarki (tj. IE 7,8,9, FF, Chrome itp.).

Z góry dziękuję za cenne sugestie.

Chetan
źródło

Odpowiedzi:

107

Selektory CSS działają znacznie lepiej niż Xpath i jest to dobrze udokumentowane w społeczności Selenium. Oto kilka powodów,

  • Silniki Xpath są różne w każdej przeglądarce, dlatego są niespójne
  • IE nie ma natywnego silnika xpath, dlatego selen wstrzykuje własny silnik xpath w celu zapewnienia kompatybilności z jego API. Dlatego tracimy przewagę korzystania z natywnych funkcji przeglądarki, które WebDriver nieodłącznie promuje.
  • Xpath ma tendencję do stawania się złożonym i dlatego moim zdaniem jest trudny do odczytania

Są jednak sytuacje, w których musisz użyć xpath, na przykład wyszukując element nadrzędny lub szukając elementu po jego tekście (nie polecałbym później).

Możesz przeczytać bloga Simona tutaj . Zaleca również CSS zamiast Xpath.

Jeśli testujesz zawartość, nie używaj selektorów zależnych od zawartości elementów. To będzie koszmar konserwacji dla każdej lokalizacji. Spróbuj porozmawiać z programistami i użyj technik, których używali do eksternalizacji tekstu w aplikacji, takich jak słowniki lub pakiety zasobów itp. Oto mój blog, który szczegółowo wyjaśnia to.

edytuj 1

Dzięki @parishodak, oto link, który zawiera liczby potwierdzające, że wydajność CSS jest lepsza

nilesh
źródło
7
Selektory CSS nie zezwalają na tekst. „Zawiera” jest przestarzałe w CSS. Jak powiedziałem powyżej, mają selektory niezależne od treści. Treść może znajdować się na zewnątrz. Możesz porozmawiać z programistami. Musieli uzewnętrznić tekst. Przez większość czasu mają słowniki dla danego regionu. Zatem klucze w słownikach są takie same, ale wartości zmieniają się zgodnie z ustawieniami regionalnymi. Możesz użyć tych plików do sprawdzenia zawartości. Zauważ, że musisz przekonwertować natywne znaki na znaki ascii za pomocą narzędzia nativ2ascii z JDK. Muszę napisać o tym blog. Za pomocą tej techniki przetestowałem wiele lokalizacji.
nilesh
1
@Chetan चेतन W odpowiedzi dodałem link do mojego bloga. Przepraszam, że zajęło to trochę czasu. Mam nadzieję, że to ci pomoże.
nilesh
8
@Nilesh: Nie zgadzam się z twoją odpowiedzią. 1.) Silniki CSS są również różne w każdej przeglądarce. To nie jest argument. 3.) Z pewnym doświadczeniem XPath jest bardzo łatwy do zrozumienia i oferuje więcej funkcji niż CSS. Jeśli szukasz bardzo zagnieżdżonego elementu, oba są złożone: XPath i CSS. Z mojego doświadczenia wynika, że ​​każda ogólna odpowiedź na to pytanie będzie błędna. Decyzja CSS / XPATH musi być podjęta indywidualnie. Pierwotne pytanie dotyczyło wydajności. Twoja odpowiedź składa się głównie z przypuszczeń i osobistych opinii. Prawdziwym dowodem byłoby ZMIERZENIE wydajności i opublikowanie wyników tutaj.
Elmue,
2
Bardzo dobry artykuł, który zaprzecza Twojemu pierwszemu zdaniu: „Selektory CSS działają znacznie lepiej niż Xpath”. To nie jest takie proste, może być wręcz odwrotnie. Oraz: „IE nie ma natywnego silnika xpath, dlatego selen wstrzykuje swój własny silnik xpath w celu zapewnienia kompatybilności z jego API”. Tutaj selen cierpi z powodu błędu projektowego. Z pewnością byłoby lepiej zaimplementować silnik XPath w C ++ zamiast skryptu java. Ale IE nie żyje, teraz pojawia się Edge. Za wszystkimi pytaniami dotyczącymi wydajności nie można zapominać, że w CSS brakuje bardzo ważnych funkcji, takich jak wyszukiwanie tekstu elementu.
Elmue
2
elementalselenium.com/tips/32-xpath-vs-css zawiera testy porównawcze sugerujące, że css3 nie jest już znacznie szybszy.
mc0e
46

Mam zamiar trzymać się niepopularnej opinii w tagach selenu SO, że XPath jest lepszy niż CSS w dłuższej perspektywie.

Ten długi post ma dwie sekcje - najpierw umieszczę dowód z tyłu serwetki, że różnica w wydajności między nimi wynosi 0,1-0,3 milisekundy (tak; to 100 mikrosekund ) , a potem podzielę się opinią, dlaczego XPath jest potężniejszy.


Różnica w wydajności

Najpierw zajmijmy się „słoniem w pokoju” - ta ścieżka jest wolniejsza niż css.

Przy obecnej mocy procesora (czytaj: cokolwiek x86 wyprodukowano od 2013 roku) , nawet na maszynach wirtualnych browserstack / saucelabs / aws i rozwoju przeglądarek (czytaj: wszystkie popularne w ciągu ostatnich 5 lat) to prawie nie ma miejsca. Silniki przeglądarki rozwinęły się, wsparcie dla xpath jest jednolite, IE nie ma na myśli (miejmy nadzieję, że dla większości z nas) . To porównanie w drugiej odpowiedzi jest przytaczane wszędzie, ale jest bardzo kontekstowe - ilu z nich działa - lub obchodzi - automatyzację przeciwko IE8?

Jeśli jest różnica, jest to ułamek milisekundy .

Jednak większość frameworków wyższego poziomu i tak dodaje co najmniej 1 ms narzutu nad wywołaniem surowego selenu (opakowania, programy obsługi, przechowywanie stanu itp.); moja ulubiona broń - RobotFramework - dodaje co najmniej 2 ms, które z przyjemnością poświęcę dla tego, co zapewnia. Podróż w obie strony z AWS us-east-1 do centrum BrowserStack trwa zwykle 11 milisekund .

Tak więc w przypadku zdalnych przeglądarek, jeśli istnieje różnica między xpath i css, jest ona przyćmiona przez wszystko inne, pod względem wielkości.


Pomiary

Nie ma zbyt wielu porównań publicznych (tak naprawdę widziałem tylko cytowane) , więc - oto przybliżony pojedynczy przypadek, atrapa i prosty.
Lokalizuje element za pomocą dwóch strategii X razy i porównuje średni czas dla tego.

Cel - strona docelowa BrowserStack i jej przycisk „Zarejestruj się”; zrzut ekranu HTML podczas pisania tego postu:

wprowadź opis obrazu tutaj

Oto kod testowy (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))

Dla niezaznajomionych z Pythonem - otwiera stronę i wyszukuje element - najpierw z lokalizatorem css, potem z xpath; operacja wyszukiwania jest powtarzana 1000 razy. Dane wyjściowe to całkowity czas w sekundach dla 1000 powtórzeń i średni czas jednego znalezienia w milisekundach.

Lokalizatory to:

  • for xpath - "element div mający dokładnie taką wartość klasy, gdzieś w DOM";
  • css jest podobny - „element div z tą klasą, gdzieś w DOM”.

Celowo wybrany, aby nie być przestrojonym; również selektor klasy jest cytowany w css jako „drugi najszybszy po id”.

Środowisko - Chrome v66.0.3359.139, chromedriver v2.38, cpu: ULV Core M-5Y10 zwykle pracujący z częstotliwością 1,5 GHz (tak, "edytor tekstu", nawet nie zwykła bestia i7) .

Oto wynik:

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

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

Oczywiście czasy na znalezienie są dość bliskie; różnica wynosi 0,32 milisekundy . Nie przeskakuj "xpath jest szybszy" - czasami tak jest, czasami jest to css.


Spróbujmy z innym zestawem lokalizatorów, trochę bardziej skomplikowanym - atrybutem posiadającym podciąg (powszechne podejście przynajmniej dla mnie, podążanie za klasą elementu, gdy jego część ma znaczenie funkcjonalne) :

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

Te dwa lokalizatory są ponownie semantycznie takie same - „znajdź element div mający w swojej klasie atrybut ten podciąg”.
Oto wyniki:

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

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

Diff z 0.15ms .


Jako ćwiczenie - ten sam test, co w przypadku linku na blogu w komentarzach / innej odpowiedzi - strona testowa jest publiczna, podobnie jak kod testowy .

Robią kilka rzeczy w kodzie - klikają kolumnę, aby posortować według niej, następnie pobierają wartości i sprawdzają, czy sortowanie w interfejsie użytkownika jest poprawne.
Wytnę to - w końcu weź lokalizatory - to jest test rootowania, prawda?

Ten sam kod co powyżej, z tymi zmianami w:

  • Adres URL to teraz http://the-internet.herokuapp.com/tables; są 2 testy.

  • Lokalizatory pierwszego z nich - „Wyszukiwanie elementów według identyfikatora i klasy” - to:

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

A oto wynik:

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

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

Różnica 0,2 milisekundy.

„Znajdowanie elementów przez przechodzenie”:

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

Wynik:

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

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

Tym razem jest to 0,5 ms (odwrotnie, xpath okazał się tutaj „szybszy”).

Tak więc 5 lat później (lepsze silniki przeglądarek) i skupiając się tylko na wydajności lokalizatorów (brak działań typu sortowanie w interfejsie użytkownika itp.), To samo stanowisko testowe - praktycznie nie ma różnicy między CSS a XPath.


A więc z xpath i css, który z dwóch wybrać pod kątem wydajności? Odpowiedź jest prosta - wybierz lokalizację według identyfikatora .

Krótko mówiąc, jeśli identyfikator elementu jest unikalny (zgodnie ze specyfikacją), jego wartość odgrywa ważną rolę w wewnętrznej reprezentacji DOM w przeglądarce i dlatego jest zwykle najszybszy.

Jednak unikalne i stałe (np. Nie generowane automatycznie) identyfikatory nie zawsze są dostępne, co prowadzi nas do pytania „dlaczego XPath, skoro istnieje CSS?”


Zaleta XPath

Skoro wydajność nie jest widoczna, dlaczego myślę, że xpath jest lepszy? Prostota - wszechstronność i moc.

Xpath to język opracowany do pracy z dokumentami XML; jako taka pozwala na znacznie potężniejsze konstrukcje niż css.
Na przykład nawigacja w każdym kierunku w drzewie - znajdź element, następnie przejdź do jego dziadka i poszukaj jego dziecka o określonych właściwościach.
Pozwala na osadzone warunki boolowskie - cond1 and not(cond2 or not(cond3 and cond4)); wbudowane selektory - „znajdź element div mający te elementy podrzędne z tymi atrybutami, a następnie przejdź zgodnie z nim”.
XPath umożliwia wyszukiwanie w oparciu o wartość węzła (jego tekst) - jakkolwiek jest to niezadowolone z tej praktyki, przydaje się, zwłaszcza w dokumentach o złej strukturze (brak określonych atrybutów do nadepnięcia, takich jak dynamiczne identyfikatory i klasy - zlokalizuj element według tekstu zawartość) .

Wkraczanie w css jest zdecydowanie łatwiejsze - można zacząć pisać selektory w ciągu kilku minut; ale po kilku dniach użytkowania, moc i możliwości xpath szybko pokonuje css.
I czysto subiektywne - złożony css jest znacznie trudniejszy do odczytania niż złożone wyrażenie xpath.

Outro;)

Wreszcie znowu bardzo subiektywne - który wybrać?

IMO, nie ma dobrego lub złego wyboru - są to różne rozwiązania tego samego problemu i należy wybrać to, co jest bardziej odpowiednie do pracy.

Będąc „fanem” XPath, nie wstydzę się używać w swoich projektach mieszanki obu - do diabła, czasami o wiele szybciej jest po prostu wrzucić CSS, jeśli wiem, że zadziała dobrze.

Todor Minakov
źródło
Ile węzłów ma stronę logowania? Strony logowania są zwykle bardzo proste, dlatego możesz zauważyć niewielką różnicę.
pagep
Inne testy wydajności pokazują znacznie większą różnicę między różnymi przeglądarkami.
pagep
1
Na pierwsze pytanie - w odpowiedzi znajduje się zrzut ekranu DOMU, a strona jest dostępna publicznie i online. Po pierwsze i drugie, jeśli uważnie przeczytasz odpowiedź, powtórzyłem ten sam test, co elementalselenium, jedno z niewielu dostępnych porównań, które jest dość często cytowane, używając tego samego celu i lokalizatorów co oni, ale tylko z 5 latami nowszymi przeglądarkami .
Todor Minakov
3
@TodorMinakov WIELKI POST !!! Zgadzam się z tobą w 100%. Uważam też, że składnia XPath jest też bardziej naturalna (przynajmniej dla mnie), ponieważ przypomina coś, co wszyscy bardzo dobrze znamy. I to są ścieżki do plików / folderów. Myślę więc, że osoba bez znajomości CSS lub XPath znacznie łatwiej nauczy się XPath. Ponieważ różnica w wydajności jest znikoma, myślę, że krzywa uczenia się zasługuje na poważne rozważenie.
hfontanez
1
Dziękuję @hfontanez; świetna analogia ze strukturą systemu plików, nie pomyślałem o tym. Muszę się jednak trochę nie zgodzić, jeśli chodzi o łatwość wkraczania - składnia XPath może na początku być nieco onieśmielająca, a ponadto ma kilka gotcha-s ( na przykład indeks []po //) . Ale po pierwszym dniu nauki i korzystania z niego prawie każdy przekracza punkt krytyczny krzywej uczenia się :) (krok CSS jest wprawdzie łatwiejszy, IMHO) .
Todor Minakov
13

Debata pomiędzy cssSelector a XPath pozostałaby jedną z najbardziej subiektywnych debat w społeczności Selenium . To, co już wiemy, można podsumować jako:

  • Osoby opowiadające się za cssSelector twierdzą, że jest on bardziej czytelny i szybszy (zwłaszcza gdy działa z Internet Explorerem).
  • Chociaż zwolennicy XPath twierdzą, że jest to możliwe w poprzek strony (podczas gdy cssSelector nie może).
  • Przechodzenie przez DOM w starszych przeglądarkach, takich jak IE8, nie działa z cssSelector, ale działa dobrze z XPath .
  • XPath może przejść w górę DOM (np. Od dziecka do rodzica), podczas gdy cssSelector może przejść tylko w dół DOM (np. Od rodzica do dziecka)
  • Jednak brak możliwości przejścia przez DOM z cssSelector w starszych przeglądarkach niekoniecznie jest złą rzeczą, ponieważ jest bardziej wskaźnikiem, że Twoja strona ma kiepski wygląd i może skorzystać na przydatnych znacznikach.
  • Ben Burton wspomina, że ​​powinieneś używać cssSelector, ponieważ tak budowane są aplikacje. To sprawia, że ​​testy są łatwiejsze do napisania, omówienia i pomocy innych osób.
  • Adam Goucher mówi, że należy przyjąć bardziej hybrydowe podejście - skupiając się najpierw na identyfikatorach, następnie na cssSelector i korzystaniu z XPath tylko wtedy, gdy jest to potrzebne (np. Chodzenie po DOM), a XPath zawsze będzie potężniejszy dla zaawansowanych lokalizatorów.

Dave Haeffner przeprowadził test na stronie z dwiema tabelami danych HTML , jedna jest zapisana bez pomocnych atrybutów ( ID i Klasa ), a druga z nimi. Szczegółowo przeanalizowałem procedurę testową i wyniki tego eksperymentu w dyskusji. Dlaczego powinienem używać selektorów cssSelector zamiast XPath do testów automatycznych? . Chociaż ten eksperyment wykazał, że każda strategia lokalizatora jest w miarę równoważna w różnych przeglądarkach, nie przedstawił nam odpowiednio całego obrazu. Dave Haeffner w innej dyskusji Css Vs. Ścieżka X pod mikroskopemwspomniano, w teście end-to-end, było wiele innych zmiennych w grę starcie Sauce , Przeglądarka rozruchu i opóźnienia do i z zastosowania badanego. Niefortunnym wnioskiem z tego eksperymentu może być to, że jeden sterownik może być szybszy od drugiego (np. IE vs Firefox ), podczas gdy w rzeczywistości wcale tak nie było. Aby uzyskać prawdziwy smak różnicy w wydajności między cssSelector i XPath, musieliśmy sięgnąć głębiej. Zrobiliśmy to, uruchamiając wszystko z lokalnego komputera, używając narzędzia do testowania wydajności. Skoncentrowaliśmy się również na konkretnym działaniu Selenium, a nie na całym przebiegu testowym, i uruchamialiśmy wiele razy. Szczegółowo przeanalizowałem konkretną procedurę testową i wynik tego eksperymentu w dyskusji cssSelector vs XPath dla selenu . Jednak w testach nadal brakowało jednego aspektu, tj. Większego pokrycia przeglądarki (np. Internet Explorer 9 i 10) oraz testów na większej i głębszej stronie.

Dave Haeffner w kolejnej dyskusji Css Vs. X Path, Under a Microscope (Część 2) wspomina, aby upewnić się, że wymagane testy porównawcze są uwzględnione w najlepszy możliwy sposób, musimy rozważyć przykład, który pokazuje dużą i głęboką stronę .


Konfiguracja testowa

Aby zademonstrować ten szczegółowy przykład, skonfigurowano maszynę wirtualną Windows XP i zainstalowano Ruby (1.9.3) . Zainstalowano również wszystkie dostępne przeglądarki i odpowiadające im sterowniki przeglądarki Selenium. Do testów porównawczych benchmarkużyto standardowej biblioteki Rubiego .


Kod testowy

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

Wyniki

UWAGA : Dane wyjściowe są w sekundach, a wyniki dotyczą całkowitego czasu wykonania 100 uruchomień.

W formie tabeli:

css_xpath_under_microscopev2

W formie wykresu:

  • Chrome :

chart-chrome

  • Firefox :

chart-firefox

  • Internet Explorer 8 :

chart-ie8

  • Internet Explorer 9 :

chart-ie9

  • Internet Explorer 10 :

chart-ie10

  • Opera :

chart-opera


Analiza wyników

  • Chrome i Firefox są wyraźnie dostrojone pod kątem szybszej wydajności cssSelector .
  • Internet Explorer 8 to zbiór cssSelector , który nie działa, przeglądanie XPath poza kontrolą, które zajmuje ~ 65 sekund, oraz 38-sekundowe przeszukiwanie tabeli bez wyniku cssSelector do porównania.
  • W IE 9 i 10 XPath jest ogólnie szybszy. W Safari jest to rzut do góry, z wyjątkiem kilku wolniejszych przebiegów przechodzenia z XPath . W prawie wszystkich przeglądarkach przechodzenie przez zagnieżdżone rodzeństwo i przechodzenie przez komórki tabeli za pomocą XPath są kosztowną operacją.
  • Nie powinno to dziwić, ponieważ lokalizatory są kruche i nieefektywne i musimy ich unikać.

Podsumowanie

  • Ogólnie rzecz biorąc, istnieją dwie sytuacje, w których XPath jest znacznie wolniejszy niż cssSelector . Ale można ich łatwo uniknąć.
  • Różnica w wydajności jest nieco na korzyść dla przeglądarek innych niż IE i nieco na korzyść dla przeglądarek IE.

Drobnostki

Możesz wykonać benchmarking samodzielnie, korzystając z tej biblioteki, w której Dave Haeffner zawarł cały kod.

DebanjanB
źródło