Piotr Pomykała
Senior IT Delivery Engineer
Automatyzacja testów odgrywa kluczową rolę w zapewnieniu wydajności, bezpieczeństwa i jakości dostarczanych rozwiązań. Umożliwia szybkie i skuteczne testowanie złożonych funkcjonalności, minimalizując ryzyko błędów i zapewniając zgodność z regulacjami.
Strategia automatyzacji testów dla T24 jest kluczowa i powinna być spójna we wszystkich NWU (Network Unit) T24. Musi być dobrze zaplanowana i uwzględniać następujące cele strategiczne:
Jednak automatyzacja testów to nie coś, czego można się nauczyć w ciągu kilku chwil. Aby rozpocząć tworzenie pierwszych skryptów, trzeba posiadać wiedzę na temat testów manualnych, tj. umiejętność „klikania” po aplikacji i znajdowania „interesujących” przypadków. Przydatne są również umiejętności myślenia koncepcyjnego, aby nie duplikować funkcjonalności. Ważne jest także posiadanie pewnych umiejętności programistycznych, chociaż można je zdobyć z czasem.
Dodatkowo na rynku pojawiło się szereg potężnych aplikacji wspierających proces pisania lub nagrywania testów automatycznych. Są to na przykład: Kalaton czy Ranorex Studio.
Dla testowania T24 przyjąłem podejście, w którym wykorzystałem narzędzie Selenium WebDriver, pisząc framework testowy w językach java i c#. Jeśli chodzi o działanie, T24 Frontend (przeglądarka) jest bardzo potężny. Spędziłem dużo czasu analizując aplikację webową pod kątem struktury drzewa DOM, wyglądu poszczególnych elementów, takich jak pola wejściowe, radiobutton, listy rozwijane itp. Zauważyłem pewne podobieństwa między nimi i postanowiłem, że mój framework zoptymalizuje kod w możliwie najwyższym stopniu, obsłuży te elementy i wyeliminuje powtarzającą się funkcjonalność na każdej zakładce.
Opracowałem szereg uniwersalnych metod. Dzięki kilkunastu z nich można obsłużyć prawie wszystkie pola w aplikacji. Na przykład: tylko dwie metody zostały napisane do obsługi „menu” i „submenu”, używając jedynie nazwy pola, wprowadzonego jako parametr ‘%s’:
String menuNameLocator = "//ul[@id='menu']/li[@class='listItemactive']/ul[@class='submenu']/li/a/span[text()='%s']"; String submenuNameLocator = "//ul[@id='menu']/li[@class='listItemactive']/ul[@class='submenu']/li[@class='listItem active']//span[text()='%s']"; |
String menuNameLocator = "//ul[@id='menu']/li[@class='listItemactive']/ul[@class='submenu']/li/a/span[text()='%s']"; String submenuNameLocator = "//ul[@id='menu']/li[@class='listItemactive']/ul[@class='submenu']/li[@class='listItem active']//span[text()='%s']"; |
Są one następnie wyszukiwane na stronie i definiowane jako WebElement. Polega to na tym, że część selektora jest definiowana jako ciąg tekstowy, a dopiero podczas testu wartość (nazwa pola) jest podstawiana do tekstu i całość jest wyszukiwana jako selektor.
Podobnie definiowane są pola tekstowe, listy rozwijane, pola wyboru czy radiobutton. Niektóre selektory są definiowane z wieloma warunkami, np.:
String elementMultiField = "//[text()=''{0}'']//ancestor::div[contains(@id,''row_QUE'')]//input[@title] " + |
String elementMultiField = "//[text()=''{0}'']//ancestor::div[contains(@id,''row_QUE'')]//input[@title] " + |
Dzieje się tak, ponieważ pola w różnych punktach procesu wyglądają tak samo, ale ich obsługa wygląda inaczej. Aby nie tworzyć dodatkowych metod, zdecydowałem się na takie rozwiązanie.
| public void CreateUser() { pages.leftMenuPage.clickShowLeftMenu(); pages.leftMenuPage.clickUserMenu(); pages.leftMenuPage.chooseMenu("Customer"); pages.leftMenuPage.chooseSubmenu("Individual Customer"); pages.newCustomerIndividualPage.clickCustomerTabSelect("Title","MR"); pages.newCustomerIndividualPage.clickCustomerTabSelect("Marital Status","Married"); pages.newCustomerIndividualPage.chooseRadiobutton("Gender","MALE"); pages.newCustomerIndividualPage.sendTextField("Given Name", "given qwert"); pages.newCustomerIndividualPage.sendTextField("Family Name", "family qwert"); pages.newCustomerIndividualPage.sendTextField("Full Name", "full qwery"); pages.newCustomerIndividualPage.sendTextField("Short Name", "short name"); pages.newCustomerIndividualPage.sendTextField("Target", "1"); pages.newCustomerIndividualPage.sendTextField("Account Officer", "2"); pages.newCustomerIndividualPage.sendTextField("Second Officer.1", "1001"); pages.newCustomerIndividualPage.addMultiField("Second Officer", 1); pages.newCustomerIndividualPage.sendTextField("Second Officer.2", "2002"); pages.newCustomerIndividualPage.sendTextField("Nationality", "PL"); pages.newCustomerIndividualPage.sendTextField("Industry", "1000"); pages.newCustomerIndividualPage.sendTextField("Customer Status", "1"); pages.newCustomerIndividualPage.sendTextField("Residence", "PL"); pages.newCustomerIndividualPage.sendTextField("Date of Birth", "1988-11-12"); pages.newCustomerIndividualPage.sendTextField("Sector", "10001"); pages.newCustomerIndividualPage.waitToScreenMaskDisappear(); pages.newCustomerIndividualPage.clickCustomerTabSelect("Customer Type","Prospect"); pages.newCustomerIndividualPage.chooseRadiobutton("Vulnerability.1","Hearing impaired"); pages.newCustomerIndividualPage.addMultiField("Vulnerability", 1); pages.newCustomerIndividualPage.chooseRadiobutton("Vulnerability.2","Visually impaired"); pages.newCustomerIndividualPage.sendTextField("Mnemonic", "MNEM001"); pages.newCustomerIndividualPage.clickCommit(); pages.newCustomerIndividualPage.waitToScreenMaskDisappear(); pages.newCustomerIndividualPage.checkIsProcessComplete(); } |
| public void CreateUser() { pages.leftMenuPage.clickShowLeftMenu(); pages.leftMenuPage.clickUserMenu(); pages.leftMenuPage.chooseMenu("Customer"); pages.leftMenuPage.chooseSubmenu("Individual Customer"); pages.newCustomerIndividualPage.clickCustomerTabSelect("Title","MR"); pages.newCustomerIndividualPage.clickCustomerTabSelect("Marital Status","Married"); pages.newCustomerIndividualPage.chooseRadiobutton("Gender","MALE"); pages.newCustomerIndividualPage.sendTextField("Given Name", "given qwert"); pages.newCustomerIndividualPage.sendTextField("Family Name", "family qwert"); pages.newCustomerIndividualPage.sendTextField("Full Name", "full qwery"); pages.newCustomerIndividualPage.sendTextField("Short Name", "short name"); pages.newCustomerIndividualPage.sendTextField("Target", "1"); pages.newCustomerIndividualPage.sendTextField("Account Officer", "2"); pages.newCustomerIndividualPage.sendTextField("Second Officer.1", "1001"); pages.newCustomerIndividualPage.addMultiField("Second Officer", 1); pages.newCustomerIndividualPage.sendTextField("Second Officer.2", "2002"); pages.newCustomerIndividualPage.sendTextField("Nationality", "PL"); pages.newCustomerIndividualPage.sendTextField("Industry", "1000"); pages.newCustomerIndividualPage.sendTextField("Customer Status", "1"); pages.newCustomerIndividualPage.sendTextField("Residence", "PL"); pages.newCustomerIndividualPage.sendTextField("Date of Birth", "1988-11-12"); pages.newCustomerIndividualPage.sendTextField("Sector", "10001"); pages.newCustomerIndividualPage.waitToScreenMaskDisappear(); pages.newCustomerIndividualPage.clickCustomerTabSelect("Customer Type","Prospect"); pages.newCustomerIndividualPage.chooseRadiobutton("Vulnerability.1","Hearing impaired"); pages.newCustomerIndividualPage.addMultiField("Vulnerability", 1); pages.newCustomerIndividualPage.chooseRadiobutton("Vulnerability.2","Visually impaired"); pages.newCustomerIndividualPage.sendTextField("Mnemonic", "MNEM001"); pages.newCustomerIndividualPage.clickCommit(); pages.newCustomerIndividualPage.waitToScreenMaskDisappear(); pages.newCustomerIndividualPage.checkIsProcessComplete(); } |
Framework oparty jest na „Page Object Model”, tj. każda „strona” to osobny obiekt/klasa w kodzie. Na przykład „strona logowania” to osobna strona, strona widoczna po zalogowaniu to kolejna, a strona, na której wypełnia się dane klienta lub konta to jeszcze inna.
Korzystając z narzędzia do budowania projektów „Maven”, mogę kontrolować parametry frameworku, takie jak: „profile”, np. do zmiany URL środowiska, nazwy użytkownika, hasła lub wielu innych, które będą potrzebne podczas testowania. W zależności od języka programowania, buduję testy na podstawie frameworku testowego java - TestNG i c# - Nunit.
Na rynku dostępnych jest wiele narzędzi do raportowania wyników testów automatycznych. Z racji ich możliwości i potrzeb, możemy używać prostych bibliotek, takich jak ExtentReport, lub bardziej rozbudowanych, takich jak Allure.
To, co przedstawiłem, to tylko kropla w morzu możliwości. Dzięki wszechstronności i szybkiej adaptacji testów automatycznych do wielu wersji T24 (takich jak R21, R22, R23 czy R24), można je wdrożyć w krótkim czasie i od razu wykorzystać do testów regresyjnych. Na początku trzeba tylko poświęcić trochę czasu na dostosowanie głównie placeholderów różnych elementów, zbudowanie przepływu przypadków testowych i baz scenariuszy. Po zakończeniu integracji, pozostaje już tylko skryptowanie, wykorzystując - jak wspomniałem - kilkanaście metod.
Automatyzacja testów ma szeroki i zróżnicowany wpływ na różne obszary systemu T24 Core Banking, od poprawy jakości i bezpieczeństwa, przez zapewnienie zgodności z regulacjami, po optymalizację kosztów i przyspieszanie innowacji. Automatyzacja jest kluczowa dla zapewnienia stabilności, skalowalności i niezawodności.
Opracowany framework T24 to nasz pierwszy krok w kierunku standaryzacji testowania T24. Razem z NWU T24 mamy jeszcze wiele do zrobienia, ale wierzymy, że silna współpraca ze wszystkimi NWU umożliwi wkrótce opracowanie standardów rozwoju i wspólnych narzędzi, które będą mogły być wykorzystywane w wszystkich NWU T24.
Senior IT Delivery Engineer