W artukule JUnit 5 i Selenium - Odpowiedzialność metod testowych wprowadziłem zmiany, które poprawiły podział odpowiedzialności metod testowych w projekcie testów automatycznych dla aplikacji TodoMVC. Kolejnym ulepszeniem będzie wydzielenie odpowiednich metod prywatnych do oddzielnych klas i wprowadzenie wzorca Page Object
.
O serii
Czytasz część 3 serii artykułów na temat automatyzacji testów aplikacji internetowej TodoMVC. Pozostałe części:
- Część 1 - JUnit 5 i Selenium - Wprowadzenie do projektu automatycznych testów aplikacji internetowej
- Część 2 - JUnit 5 i Selenium - Odpowiedzialność metod testowych
- Część 4 - JUnit 5 i Selenium - Optymalizacja konfiguracji i uruchomienia projektu
- Część 5 - JUnit 5 i Selenium - klasa PageFactory z pakietu support biblioteki Selenium
Kod źródłowy
Kod źródłowy opracowany w poprzednim artykule znajduje się w repozytorium Git
: https://gitlab.com/qalabs/blog/junit5-selenium-todomvc-example w branchu 2-tests-responsibility
. Klasa testowa, która zostanie zmodyfikowana w tym artykule, to TodoMvcTests
, do jej kodu można przejść bezpośrednio po kliknięciu w link pl.qalabs.blog.junit5.selenium.todomvc.TodoMvcTests.
Rozdzielenie warstw
Po ostatnich zmianach w kodzie projektu możemy wyszczególnić trzy warstwy odpowiedzialności:
1 | // warstwa 1 - logika testu |
W kolejnych krokach usprawnię kod w taki sposób, aby poszczególne warstwy znalazły się w oddzielnych klasach i pakietach.
Logika Aplikacji - Page Object Pattern
Logika aplikacji (zawarta dotychczas w ogólnej klasie TodoMvcTests
, z grubsza pomiędzy liniami 130 i 210 zostanie wyniesiona do klasy odpowiedzialnej tylko i wyłącznie za dostarczenie API
związanego z obsługą strony TodoMvc
. W naszym przykładzie API
to jest reprezentowane przez pojedynczą klasę TodoMvc
, która zawiera publiczne metody manipulacji interfejsem użytkownika:
1 | public class TodoMvc { |
Ważną cechą nowej klasy jest to, że nie udostępnia swoim klientom (w naszym przypadku klasie testowej) żadnych informacji dotyczących obsługi WebDriver API
. Ta obsługa jest realizowana przez obiekt klasy Browser
, przekazany za pomocą konstruktora (o samej klasie Browser
przeczytasz w dalszej części artykułu).
Jeżeli przyjrzymy się dokładniej metodom klasy TodoMvc
to zauważymy, że udostępnia ona metody odzwierciedlające funkcje testowanej strony (page), w tym funkcję nawigacji do strony (metoda navigateTo()
). Zatem klasa TodoMvc
jest obiektem typu Page Object
, gdyż reprezentuje funkcjonalność konkretnej strony, ukrywając jednocześnie szczegóły komunikacji z przeglądarką.
Używanie Page Objects
w naszym teście jest bardzo proste: wystarczy zainicjalizować obiekt strony i wywoływać kolejne metody, weryfikując jednocześnie, czy zachowanie strony jest zgodne z oczekiwanym:
1 |
|
Browser Object
Obiekt TodoMvc
potrzebuje dostępu do przeglądarki w celu zautomatyzowania poszczególnych funkcji aplikacji. Dostęp ten jest zrealizowany przez obiekty WebDriver API
, a klasę, która opakowuje ten dostęp, nazwałem Browser
. Klasa Browser
dostarcza metody zawarte dotychczas w ogólnej klasie TodoMvcTests
(pomiędzy liniami 212 i 251:
1 | public class Browser { |
Klasa Browser
zawiera metodę statyczną newBrowser()
, która pozwoli na inicjalizację sterownika przeglądarki. Pozostałe metody klasy Browser
upraszczają korzystanie z WebDriver API
w naszym projekcie. Obiekt klasy Browser
inicjalizowany jest w metodzie @BeforeEach
i następnie przekazywany do obiektu TodoMvc
, który wykorzysta go do automatyzacji kolejnych funkcji aplikacji.
Tip: Jeżeli w trakcie implementowania
Page Object
okazałoby się, że potrzebuje bezpośredniego dostępu doWebDriver API
, moglibyśmy stworzyć dodatkową metodę np.public RemoteWebDriver getWebDriver() {}
i przy jej pomocy wyeksponować użyty sterownik przeglądarki.
Warto zwrócić uwagę na inną nową metodę, browser.quit()
, której nie było we wcześniejszej wersji kodu. Metoda ta odpowiada za zamknięcie sterownika i wykorzystana została w teście:
1 |
|
Struktura pakietów
Po zmianach wprowadzonych powyżej uzyskaliśmy trzy klasy: TodoMvcTests
, TodoMvc
oraz Browser
. Klasy te znajdują się aktualnie w tym samym pakiecie. Warto jednak pomyśleć o wydzieleniu klas do oddzielnych pakietów, tak aby zwiększyć czytelność kodu i ułatwić jego rozbudowę w przyszłości. Pakiety w Javie służą do grupowania podobnych typów klas czy interfejsów, zatem naturalnym będzie utworzenie pakietów dla poszczególnych rodzajów odpowiedzialności:
pl...todomvc.tests
- klasy testowe (TodoMvcTests
)pl...todomvc.pages
- klasyPage Objects
(TodoMvc
)pl...todomvc.support
- klasy wsparcia (Browser
)
Diagram klas
Ostateczny diagram klas wygląda następująco:
Warto zauważyć, że zależności między klasami bięgną w jednym kierunku. Fakt, że klasa testowa zależy od klasy Browser
, wynika wyłącznie z potrzeby inicjalizacji przeglądarki przed wykonaniem testów oraz zamknięciem jej po wykonaniu testów.
Podsumowanie
Używanie technik programowania obiektowego zwiększa jakość kodu oraz wpływa pozytywnie na utrzymanie i modyfikacje kodu w przyszłości. Sam wzorzeć Page Object
nie jest wzorcem skomplikowanym. Wymaga on jednak zrozumienia podstawowych technik projektowania obiektowego, w celu modelowania bardziej skomplikowanych stron i interakcji.
Główne korzyści wynikające z używania tego wzorca to:
- rozdzielenie odpowiedzialności między skryptami testowymi a fukcjonalnością aplikacji,
- możliwość wielokrotnego użycia obiektów,
- łatwość wprowadzania zmian, gdy funkcjonalność aplikacji się zmienia
- zwiększona czytelność kodu
Dalsze kroki
Biblioteka Selenium
dostarcza własną implementecję wzorca Page Object
. Przeczytasz o niej w części 5 tej serii: JUnit 5 i Selenium - klasa PageFactory z pakietu support biblioteki Selenium
Repozytorium Git projektu
Kod źródłowy opracowany w artykule znajduje się w repozytorium Git
: https://gitlab.com/qalabs/blog/junit5-selenium-todomvc-example w branchu 3-page-objects
.