Testowanie automatyczne. Znajdowanie elementów na stronie – Selenium WebDriver + C# część 2

Posted by in C#, Selenium, Testowanie automatyczne

Znajdowanie elementów na stronie – Testowanie automatyczne w  Selenium webDriver część 2

W dzisiejszym wpisie chcę Wam pokazać, w jaki sposób możemy znajdować elementy umieszczone na stronie, którą testujemy  w Selenium WebDriver. W tym celu utworzyłem testowego stronę na platformie blogowej na ghost.org. Polecam również stworzyć sobie stronę z ghostem do nauki Selenium.

Czym jest element?

Elementami jest wszystko to, co widzimy na stronie. Wszystko, co ma swoje odzwierciedlenie w html’u.

Dzięki znajdowaniu elementów możemy wykonywać określone akcje z nimi związane np.:

  • odczytywać tekst, jeżeli go posiadają
  • sprawdzić, czy są na stronie
  • sprawdzić, jaką mamy ilość danego elementu
  • stworzyć obiekt IWebElement, który będzie odzwierciedleniem w kodzie elementu, który znaleźliśmy na stronie (dzięki lokatorowi)
  • klikać w nie, w różny sposób
  • wpisywać wartość tekstową w znalezionym element
  • czekać aż element się pojawi

Jakie są możliwości znajdowania elementów na stronie poprzez Selenium?

W standardowym Selenium WebDriver mamy możliwość odwoływania się po tzw. lokatorach.

Lokatorem mogą być:

  • XPath
  • CssSelector
  • ClassName
  • Name
  • Id
  • LinkText
  • PartialLinkText
  • TagName

 

Polecam, jeżeli jest to możliwe odwoływać się na stronie po Id lub Name. Są one najszybciej znajdowane na stronie, jeżeli występują.

W innych przypadkach możemy użyć:

  • ClassName,
  • XPatha,
  • CssSelectora,
  • Nadać elementowi id’ka lub name,
  • LinkText
  • PartialLinkText
  • TagName

Jeżeli, jest to możliwe polecam w tym przypadku nadać id bądź name. Jednak, jeśli z jakichś powodów jest to niemożliwe, rekomenduje odwoływać się po  CssSelectorze. Jest bardziej podatny na zmianę niż id czy name. Jednak używając wzorca projektowego Page Object Model taka zmiana, zajmuję chwilę (W przyszłości napiszę post o nim).

Polecam wypowiedzi:

JimEvans’a (odpowiedzialnego za rozwój WebDrivera dla C#)

http://stackoverflow.com/questions/11777694/which-is-the-best-and-fastest-way-to-find-the-element-using-webdriver-by-xpath

http://stackoverflow.com/questions/13975595/why-one-should-prefer-using-css-over-xpath-in-ie

Czego potrzebujemy?

  • Visual Studio
  • R#
  • ChromeWebDriver
  • SeleniumWebDriver
  • Własna strona z zainstalowanym ghostem + post powitalny

Tworzymy w naszym projekcie nową klasę o nazwie FindElementsOnPage.cs

Dodajemy metodę testową z wejściem na stronę. Inicjalizujemy ChromeDrivera.

Dodajemy zmienną wraz z adresem url. W jaki sposób szukać elementów? Poniżej przedstawiam kilka dodatków, które pomagają nam w szukaniu.

Polecam cztery ciekawe dodatki, które pomagają nam znajdować XPatha oraz CSS Selectory elementów.

WebDriverLocator

Odkryty nie dawno przeze mnie dodatek do Firefoxa. Dodajemy poprzez wyszukanie WebDriver Element Locator w dodatkach Firefoxa.

Klikamy PPM na wybraną stronę w Firefoxie. W menu kontekstowym mamy dostęp do lokatorów Xpath dostosowanych do C#.

locator locator1

Dla szybkiego znalezienia XPath’a jest to pomocny dodatek.

FirePath + FireBug

https://addons.mozilla.org/en-US/firefox/addon/firepath/

Jeden z najbardziej popularnych dodatków służących do znajdowania XPatha oraz CSS Selectora na stronie. FirePath jest bardzo przyjemnym dodatkiem. Pozwala znajdować css selectory oraz XPathy szybko, ja osobiście go bardzo polecam.

FireFinder +FireBug

Dodatek, który widziałem na jednej prezentacji odnośnie Selenium WebDriver. Pozwala sprawnie radzić sobie z XPathem.

Kurs znajdowania CSS Selectorów

http://flukeout.github.io/ Prosty i przyjemny kurs podstaw znajdowania CSS Selectorów.

Chrome Developer Tools

Za pomocą Chrome Developer Tools (Klikamy F12 lub  PPM – >”zbadaj element”) możemy odczytać każdy lokator elementu na stronie www, jeżeli on istnieje. Polecam samemu nauczyć się podstawowego znajdowania. Wymieniony wyżej kurs pomaga w tym. Dlatego, że nasze css selectory czy xpathy mogą być, krótsze, bardziej odporne na zmianę interfejsu strony www niż zrobione przez automat np. Chrome’a.

find8

IWebElement

Jest to interfejs, który definiuje wszystkie metody oraz właściwości, które ma każdy obiekt WebElement.

https://seleniumhq.github.io/selenium/docs/api/dotnet/html/T_OpenQA_Selenium_IWebElement.htm

Polecam artykuł na temat interfejsu, jeżeli ktoś nie miał styczności.

http://4programmers.net/C_sharp/Interfejsy

Każdy obiekt typu WebElement obsługuje interfejs IWebElement.

find1

Gdy skopiujemy lokator danego elementu, tworzymy w kodzie obiekt typu WebElement z takim samym rodzajem lokatora, jakiego pobraliśmy wartość. Przy pomocy metod dostępnych w klasie By (klasa ta posiada dla każdego lokatora osobną metodę).

Dlaczego w przykładach mam var zamiast WebElement lub IWebElement?

Często stosuje „var”. Tym bardziej dla wartości, dla których bez zastanowienia znam wartość. Czym jest „var” wyjaśnione jest sensownie na stackOverflow:

http://stackoverflow.com/questions/4307467/what-does-var-mean-in-c

find2

Lub metody, które znajdują się poza „By”

driver.FindElementById(„id”);

driver.FindElementsByName(„name”);

Na stronie wyszukajmy:

  • Tytuł strony

find3

Klasa „page-title” w tym przypadku odpowiada za tytuł strony. Chrome podświetla nam w konsoli element na, którym kliknęliśmy „Zbadaj element” lub mając odpalone Chrome Developer Tools, najechaliśmy na ten element.

  • Opis strony

var pageDescription = driver.FindElement(By.ClassName(„page-description”));

  • Liczbę postów

Tutaj przedstawię dwa pomysły na pobranie wszystkich postów:

var listOfPostsValue = driver.FindElementById(„content”).FindElements(By.ClassName(„post-excerpt”));

Assert.AreEqual(listOfPostsValue.Count, amountOfPosts);

Dzięki temu, że w Selenium możemy szukać elementu w elemencie, zmienna listOfPostValue zwraca kolekcję WebElementów, które mają id=”content” oraz ClassName =”post-excerpt”.  Dzięki FindElements możemy znaleźć je wszystkie i zapisać do kolekcji. Po zapisie do zmiennej możliwe jest odwołanie się do dowolnego posta.

var textFromFirstPost = listOfPostsValue[0].Text;

Assert.AreEqual(textFromFirstPost, „You’re live! Nice. We’ve put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by »”);

Asercja sprawdza, czy posty posiadają tę samą treść.

Lub

var listOfPosts = driver.FindElementByClassName(„post-excerpt”).FindElements(By.TagName(„p”));

Każdy post zawiera TagName

(paragraph), w którym jest skrócona treść posta.

  • Kolekcję wszystkich tytułów postów

var allOfPostTitles= driver.FindElements(By.ClassName(„post-title”));

Assert.AreEqual(allOfPostTitles.Count,amountOfPosts);

  • Przycisk menu

Najbardziej charakterystycznym elementem, który wyróżniania przycisk menu to klasa „word”

var menuButton = driver.FindElement(By.ClassName(„word”));

Assert.AreEqual(menuButton.Text, „MENU”);

Asercja pozwala sprawdzić, czy teksty są takie same. Na wyniki wyszukiwania ma wpływ wielkość liter, więc jeżeli byśmy napisali „Menu” to test, by nie przeszedł.

  • Link do autora

Żeby uzyskać link do autora bloga (w tym przypadku testowyblog). Możemy odwołać się do LinkTextu

var linkToGhostOwner = driver.FindElementByLinkText(„testowyblog”);

Assert.AreEqual(linkToGhostOwner.Text,”testowyblog”);

Po poznaniu podstawowych opcji wyszukiwania elementów na stronie uruchamiamy test.

find4

Teraz sprawdzimy, co się stanie z testami, jeżeli dodam drugi post na platformie blogowej Ghost.

find5

Pojawia nam się błąd związany z datą. Sprawdzamy ClassName „post-date”, Selenium wskazuje nam tego posta, który jest najnowszy. Dlatego, że Selenium bierze pierwsze wystąpienie ClassName „post-date” po dodaniu posta. Najnowszy post ma to pierwsze wystąpienie. Jeżeli chcemy w teście sprawdzić datę pierwszego posta w kontekście dodania, to możemy zrobić sobie kolekcje post-data i wziąć ostatni element (post):

Np. tak

var postDates = driver.FindElements(By.ClassName(„post-date”));

Assert.AreEqual(postDates.Last().Text, „24 JULY 2016”);

Po tej zmianie w asercji test w tym miejscu. Uruchamiamy znowu. NUnit zwraca nam błąd:

find6

Wynika to z tego, że liczymy ile mamy postów (2), a w kodzie mamy zdefiniowane, że mamy jeden post. Należy zmienną amountOfPosts zmienić na 2.

Kolejna rzecz, którą należy poprawić:

find7

Post, który dodałem do strony, jest (patrząć od góry strony wyświetlany jako pierwszy). Jego długość wyności 25 znaków, nie 142 jak wcześniejszy post czyli post drugi ( Pierwszy w kontekście daty powstania ). Jeżeli chcemy sprawdzać ostatni post, to również korzystamy z Last().

var listOfPostsValue =driver.FindElementById(„content”).FindElements(By.ClassName(„post-excerpt”));

var textFromFirstPost = listOfPostsValue.Last().Text;

Assert.AreEqual(textFromFirstPost, „You’re live! Nice. We’ve put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by »”);

Jeżeli postanowilibyśmy w naszym scenariuszu, że chcemy zawsze wybierać pierwszy post (najstarszy), polecam wtedy się zastanowić:

  • Czy w jednym scenariuszu testowym dodajemy i usuwamy post?
  • Uruchamianie scenariuszy testowych jeden po drugim, w jednym scenariuszu dodajemy post, w drugim scenariuszu usuwamy wcześniej dodany post. Musimy pamiętać w tym wypadku o kolejności uruchamiania (możemy pogrupować).

Może sami macie jakiś inny ciekaw pomysł? Z chęcią go poznam. Podzielicie się koniecznie w komentarzu.

Podsumowanie

Poznaliśmy znajdowanie elementów za pomocą różnych lokatorów w Selenium WebDriver oraz C#. W kolejnym wpisie na temat selenium poruszę temat klikania w  elementy na stronie.

MS.