Page Object Model – Wzorzec, który ułatwi Wam implementowanie testów w Selenium WebDriver.

Posted by in C#, dajsiepoznac, Testowanie automatyczne

Page Object Model – Wzorzec, który jest nieodzowny w testowaniu automatycznym stron www.

Dzisiaj chcę przedstawić wam jeden z najbardziej podstawowych wzorców projektowych używany przy implementowaniu testów automatycznych. Pokażę jak w prosty sposób możecie go zastosować przy użyciu C# + Selenium WebDriver. Jeżeli ktoś z Was nie słyszał o tym wzorcu, dowie się jakie korzyści płyną z korzystania z niego w swoich testach. Przykład będzie prosty na tyle, na ile to jest możliwe.

Z tekstu dowiesz się m.in:

  • Jak budować testy, które będą łatwiejsze w utrzymaniu i implementowaniu ?
  • Jak zmniejszyć ilość duplikowanego kodu?

Czym jest Page Object Model?

 

 

folwer

 

Martin Folwer

źródło „ http://martinfowler.com/bliki/PageObject.html

Jest to sposób pisania testów polegający na tym, że każdą ze stron danej aplikacji webowej przedstawiamy jako tzw. Page object. Każdy z elementów na stronie, którą testujemy możemy przedstawić w naszej implementacji jako obiekt typu IWebElement (Może != Musi, jeżeli danego elementu znajdującego się na stronie, którą testujemy nie potrzebujemy w teście, to nie implementujemy go, by nie zaciemniać kodu).

Czego będziemy potrzebować do zdeklarowania naszego elementu w teście?

Do zdeklarowania elementu w teście potrzebujemy użyć tak jak przy deklaracji IWebElement – jakiegoś selectora. Do wyboru mamy:

  • XPath,
  • CssSelector,
  • Id,
  • Name,
  • Class,
  • PartialLinkText,
  • LinkText,

Pozwala to w jednym miejscu posiadać deklaracje obiektu IWebElement, który odpowiada elementowi na stronie. Jeżeli na stronie będzie dokonana jakaś zmiana np. selector Id przycisku zmieni się z „buttonId” na „buttonNewId” dzięki używaniu page object model – zmiany selectora dokonujemy w jednym miejscu.

Przykładowy obiekt:

[FindsBy(How=How.Id,Using = „user_login”)]

public IWebElement LoginField { get; set; }

Programista wprowadza zmianę  w html, od teraz element, który na stronie to selector user_login po zmianie to user_login_foo.  Gdy zamienimy user_login na user_login_foo to w testach w których wszędzie używaliśmy tego elementu zachodzą takie zmiany. Jeżeli nie używalibyśmy Page Object Model to w każdym teście gdzie używalibyśmy IWebElement z selectorem „user_login” trzeba byłoby zmienić na „user_login_cos”.

Po co stosować Page Object Model?

– Pozwala oddzielić logikę metod robiących akcje na stronie od reprezentacji elementów na stronie w postaci obiektów IWebElement

-Pozwala w łatwiejszy sposób zrozumieć abstrakcje związaną z pisaniem testów

-Pozwala łatwiej utrzymywać testy, jeżeli zmienia się selector na stronie np. poprzez zmianę układu strony to selector do elementu zmieniamy tylko w jednym miejscu. Jeżeli nie stosujemy Page Object Model to należy we wszystkich testach zmienić dany selector.

Przechodzimy do części napisania dwóch prostych testów, które będą korzystały ze wzorca page object model.

Co będzie Ci potrzebne?

  • Postawiona testowa strona wordpress.com.  -Ja użyję w tym celu swojego bloga, którego stworzyłem do pisania testów.(https://studytestingblog.wordpress.com/). Możesz również lokalnie postawić sobie takiego wordpressa.
  • Visual Studio

Dodane do projektu

  • ChromeDriver (przykładów nie testuje na innych driverach, więc może się zdarzyć, że kod z wpisów może inaczej się zachowywać na innych driverach).
  • Dodane przez NuGet’a:

page object model

Do projektu z testami dodaję folder Pages – Miejsce gdzie będziemy umieszczać nasze klasy z reprezentacją danego widoku na stronie.

pom3

Tworzymy plik klasy HomePage.cs

page object model

Sama klasa, którą użyje do testu wygląda tak:

  • Zaczynamy od definicji Driver, który jest/możę potrzebny do metod w Page’ach.
  • Następnie definiuje kilka elementów, które znajdują się na stronie.

https://studytestingblog.wordpress.com/wp-login.php

page object model

Aby stworzyć properites, który będzie odzwierciedlał element na stronie używamy:

[FindsBy(How= Tutaj wpisujemy jakiego selectora używamy  np. How.Id,Using = „tutaj wartość tego selectora np. user_login”)]

 LoginField  – properties, który reprezentuje pole służące do wpisywania loginu;

Selectory „zdobywamy” tak jak pokazywałem to w jednym ze wcześniejszych wpisów (link).

PasswordField – properties, który reprezentuje pole służące do wpisywania hasła;

SubmitButton – properties, który reprezentuje przycisk do wysłania formularza;

ErrorBox – propeties, który reprezentuje div’a zawierającego komunikaty o błędach (jeżeli jest na stronie np. gdy próbujemy zalogować się złym hasłem);

Po dodaniu propertiesów tworzymy konstruktor z parametrem.

Parametr jest typu IWebDriver. Powoduje to, że możemy przekazać każdy Driver, który implementuje interfejs IWebDriver. Gdybyśmy wpisali jako parametr ChromeDriver driver, zamiast IWebDriver driver to nie moglibyśmy w teście przekazać np. FirefoxDriver’a

this.Driver=driver;

Powoduje to, że nasz properties Driver będzie miał przypisaną referencje przekazanego driver’a, gdy stworzymy nowy obiekt typu HomePage.

PageFactory.InitElements(driver, this); <- Powoduje, że w konstruktorze inicjalizowane są elementy z tego Page’a. Gdybyśmy tego nie zrobili to test w miejscu gdzie używany byłby element z klasy HomePage rzuciłby błędem NullReferenceException dlatego, że element nie miałyby referencji.

pom5

Kolejnym elementem, który zaimplementujemy jest stworzenie metody odpowiadającej za logowanie do strony. Zmniejsza to ilość kodu w teście, łatwiej się go analizuje oraz nie trzeba w każdym teście pisać mechanizmu logowania.

Raz napisana metoda jest reużywalna w innych testach.

Metoda, którą napiszemy będzie zawierać:

Dwie właściwości, które są typu IWebElement (więc posiadają „po kropce” dostęp do metody SendKeys(„”);, odpowiadającej za wpisywanie znaków).

W parametrze będziemy przekazywać login i hasło.

Następnie po wpisaniu klikniemy w przycisk „Log In”  czyli w naszym przykładzie SubmitButton.Click();

Metoda jest typu DashboardPage i zwracamy return new DashboardPage(Driver);

logujemy się i test przenosi nas do Dashboard’u (Tak działa zalogowanie się do panelu admina w wordpressie).

pom6
devenv_2017-04-02_12-59-33

Po stworzeniu metody logującej tworzymy w folderze Tests folder Login. Dobre ułożenie testów po folderach pozwala zachować porządek w solucji. W folderze Login tworzymy klasę CheckLoginFunctionality.cs.  Stworzymy dwa testy, które sprawdzą w różnej konfiguracji:

  • Czy po zalogowaniu URL jest prawidłowy.
  • Czy gdy podamy złe hasło wyświetlany jest prawidłowy komunikat walidacyjny.

page object model

Testy zaczynamy od deklaracji zmiennej driver typu IWebDriver.

W setupie definiujemy zmienną driver typu ChromeDriver. Następnie przechodzimy do stworzenia w teście obiektu typu HomePage w parametrze przekazujemy obiekt driver.

CommonHelper.cs  – to klasa, która zawiera dwa properties’y. Jeden z loginem, drugi z hasłem do panelu administracyjnego.

Na końcu pierwszego testu znajduję się asercja sprawdzająca czy adres URL Driver’a jest taki jak oczekujemy po zalogowaniu. W drugim teście dodałem więcej asercji, żeby pokazać Wam jakie inne rzeczy możemy sprawdzać.

Assert.IsTrue(home.ErrorBox.Displayed) – sprawdza czy ErrorBox wyświetlił się.

Ostatnia asercja sprawdza czy komunikat walidacyjny jest prawidłowy znak po znaku.

W [TeardDown]

znajduję się metoda Close(), która zamyka po każdym teście przeglądarkę za pomocą driver.Dispose();

Próbujemy uruchomić nasz test. Testy wyświetlają się na zielono. Jednak gdy uruchamiam je drugi raz. Pojawia się błąd przy jednym z testów. Widać, że Selenium WebDriver zbyt szybko wpisuje tekst. Dodamy klasę WaitHelper.cs, która będzie zawierał metodę, która czeka na wpisanie przez selenium tekstu w pole.

Klasa WaitHelper.cs

page object model

Następnie tworzymy metodę statyczną WaitUntilElementValueEquals, która zawiera trzy parametry:

this IWebDriver driver – każdy obiekt, który implementuje IWebDriver ma dostęp do tej metody „po kropce”,

IWebElement element – element, który będziemy przekazywać i w nim sprawdzać czy wartość zdążyła się wpisać,

valueToCheck – przekazujemy tu tekst na, który będziemy czekać, aż się pojawi jako wartości w elemencie,

W pierwszej linii metody tworzymy obiekt typu WebDriverWait, który pozwala czekać za pomocą Selenium. Jako parametr potrzebuje jakiegoś driver’a, oraz TimeSpan.

Ostatnim krokiem jest wywołanie metody Unitl, która czeka w zadanym czasie na to by wartość atrybtu naszego elementu przekazengo w metodzie była równa z valueToCheck

Po stworzeniu metody dodajemy ją do klasy HomePage i metody LoginOnPage

pom8

Dodajemy naszą metodę. Uruchamiamy testy.

pom9

Podsumowanie

Dzisiaj dowiedzieliśmy się czym jest wzorzec Page Object Model. Zachęcam do wypróbowania tego u siebie.

MS.