Menü Bezárás

Dinamikus objektumelérés Robot Framework-ben

Bevezető

Ha webes tesztautomatizálási feladatot kapunk, talán az egyik legelterjedtebb módszer a rendszer objektumok elérésének a tárolására a Page Object Model. Egy weboldalon a gyakorlatban ez egyet jelent azzal, hogy a különböző beviteli mezők, gombok, és más használni kívánt teszt objektumok megfogásához szükséges adatot oldal szinten, fa struktúrában tároljuk. Minden ilyen „oldal” felel a saját objektumai eléréséért és a futtatott teszt felé történő kiszolgálásáért.

De mi van akkor, ha az egész kezd átláthatatlanná válni? Vagy túlságosan is nagy erőforrást igényel az esetleges módosulások kijavítása? Ebben a cikkben egy lehetséges alternatívát mutatok be, amelyhez nincs szükség másra csak egy kicsit kísérletezőbb gondolkodásmódra, és némileg több, együtt eltöltött időre a fejlesztővel egy hatékonyabb megoldás érdekében.

Dinamikus Selector, de mitől dinamikus?

A Page Object Model-ben az oldalról kinyert objektumelérések leggyakrabban a konkrét xpath útvonalak, vagy css selectorok, (esetleg egyéb), amelyek egyértelműen azonosítják az elemet.

A gyakorlatban, ha az oldal egy nagy form-ot tartalmaz, akkor ez egy szép hosszú beviteli mező, gomb, legördülő stb. listát fog jelenteni, amelyben minden elemnek megtalálható a saját egyedi elérési útvonala, a legtöbbször egy saját GET függvénnyel kiegészítve.

Az általam bemutatni kívánt módszer szerint az oldal elemeinek selectorait nem statikusan, egyenként adom meg, hanem előre leegyeztetett szabályoknak megfelelően építem fel őket dinamikusan, futásidőben, ily módon egy egyedi lokátor típust bevezetve.

Bár e cikkben a konkrét példák Robot Frameworkben vannak megvalósítva, de az elv könnyen átültethető egyéb tesztautomatizálásra alkalmas eszközbe is.

Szakítsunk a dogmákkal

Amikor először hallottam arról, hogy a képernyőn megjelenő szöveghez (label) kössem a teszt-objektumaim megtalálását, kissé erőt vett rajtam egyfajta fojtogató érzés, amelyet talán mindannyian ismerünk, és érzünk, ha olyasmit veszünk fontolóra, ami ellen az eddigi ismereteink agresszívan tiltakoznak.

Hiszen a megjelenített szövegek sűrűn változhatnak. Azért kötjük objektumainkat ID-khoz, class-ekhez, egyedi azonosítókhoz, hogy lehetőleg a minél több ideig használható, egyértelmű azonosításukat megoldjuk.

Ha összehasonlítjuk a Page Object Model-t és a Dinamikus Selectorok használatát, akkor figyelembe kell vennünk azt, hogy mennyi erőforrás ráfordítással jár az oldal módosítása utáni kód karbantartás:

  1. Ha csak a labelek és egyéb szövegek változnak, akkor a régi módszer jobbnak tűnhet, hiszen semmilyen munka sincs az objektumleírókkal. Amik eddig lefutottak, azok valószínűleg ezután is lefutnak, ha figyelmen kívül hagyjuk a szöveg ellenőrzéseket, amit nyilvánvalóan elbukunk az első futásnál. A label alapú dinamikus selectoroknál sajnos minden szöveget frissíteni kell, hogy újra működő kódot kapjunk. Mivel konkrét szöveget kell másik konkrét szöveggel helyettesíteni, ez általában megoldható akár file-okon keresztül is, keresés/csere funkcióval.
  2. Ha az oldal szerkezete változik, akkor már érdekesebb lehet a kérdés. Amennyiben új objektumok kerülnek be a html dokumentumba, avagy régiek kerülnek ki onnan, akkor a teszt-objektumaink elérése megváltozhat. Ez esetben újra ki kell gyűjteni az elérési útvonalakat a régi módszer szerint. Dinamikus selectorokat használva a teszteset továbbra is lefut, hisz a labelek nem változnak, és amennyiben a fejlesztővel leegyeztetett szabály az új verzióban is érvényes, akkor a szükséges módosítás,(ha egyáltalán szükséges), csak új esetek írása, vagy egyszerű teszteset pontosítás lesz, ami lényegesen kevesebb munkát igényel.

Lássuk a medvét

Ahhoz, hogy mérlegelni tudjunk, látnunk kell a gyakorlatban is, hogy mire is gondolok fejlesztővel leegyeztetett szabály alatt. Adott egy weboldal részlet (A példa INNEN van):

Aminek a beviteli mezői így néznek ki:

A cikk nem tartalmazza a teljes html-t a példáknál, csak a példák megértéséhez hasznos dolgokat. A teljes elemzéshez meg kell látogatni a http://automationpractice.com oldalt.

Ha megtekintjük az ábrát, láthatjuk, hogy az Email label és email input egy saját div-en belül helyezkedik el, és ezt a szabályt követi a Password label és input is.

Amennyiben egyeztetünk a fejlesztővel az oldal felépítését illetően, megismerhetjük az ehhez hasonló mintákat, amik során könnyen felépíthetjük az objektumaink elérését biztosító XPATH-t.

A közvetlen szülőjük közös, tehát a létrehozott szabály, amely visszaadja az inputot:
//label[contains(text(),’Email address’)]/..//input

Vegyük észre, hogy ha az ’Email address’ kifejezést kicserélem egy változóra, akkor minden olyan elemet el tudok érni, ami ilyen struktúrában szerepel az oldalon, például a Password mezőt:
${valtozo}= „Password”
//label[contains(text(),’${valtozo}’)]/..//input

Jó-jó, de mi van akkor, ha az oldalon van többszáz Mentés gomb és félmillió Email cím mező egyetlen oldalon?

Nyilvánvalóan túlzó a kérdés, de például az eredeti oldalon az alábbiképen látható elrendezésben két Email address mező található:

Ez gyakori jelenség. Általában a hasonló elnevezésű objektumok más-más célt szolgálnak, és ezért egy weboldalon más-más szekcióban foglalnak helyet. A példánkban a két szekció az „Already registered?” és a „Create an account” blokk. Ilyenkor nincs más teendőnk, mint plusz paraméterként belevenni a szekció nevét, így referálhatunk a megadott blokk megadott mezőjére.

Az eredeti oldalon a szekciók egy-egy form-ban találhatók, amik egy h3 tag-ben tartalmazzák a szekciók nevét. Így a számunkra jó XPATH:

//h3[contains(text(),’Already registered?’)]/..//label[contains(text(),’Email address’)]/..//input

Változókkal:

További előnyök:

  • A labelek használata miatt nem technikai emberek számára is könnyebben olvasható.
  • Ha dinamikus attribútumok vannak a tag-eknél, ami manapság eléggé gyakori, akkor az sem jelent problémát.
  • Ha a fejlesztő tartja magát a szabályhoz, akkor az új fejlesztésekhez szükséges tesztek legyártása sokkal könnyebb, mert csak a megfelelő label-ekkel kell megírni a tesztet és nincs szükség lokátorok kigyűjtésére.
  • Mivel a modern webfejlesztő eszközök amúgy is sablonszerűen generálnak oldalakat, így a módszer teljes mértékben illeszkedik az általuk készített kódhoz.
  • Ha az oldal mégis tartalmaz olyan elemeket, amikre nem készíthető ilyen szabály, akkor még mindig készíthetünk belőlük egy kivétellistát, amit egyedileg kezelünk le.

Megvalósítás Robot Frameworkben:

A Robot Framework-höz az alábbi kiegészítéseket használtam:

  • Selenium LibraryA webes automatizáláshoz szükséges RF-ben.
  • REDEclipse alapú szerkesztő és debugger, amit a Nokia fejlesztett.
  • PyYAML: Python könyvtár, könnyen kezelhetővé teszi YAML adatokat.

A továbbiakban a Robot Framework, valamint a fenti eszközök telepítésére és beállítására nem térek ki, de könnyedén találhatunk leírásokat és segítséget a neten, ha rászánunk egy kis időt a kutakodásra. Robot Framework megismeréséhez ajánlom Szőke Ármin a témával foglalkozó „Tesztautomatizálás Robot Framework segítségével 1.rész” cikkét.

A feladat:

Regisztrációs folyamatot szeretnék automatizálni az http://automationpractice.com/ oldalon.
A folyamat 3 oldalt érint:

Segédeszköz:

Selenium Library-ben van egy olyan lehetőség, hogy saját lokátort (tehát szabályt) lehet készíteni. Ezt az alábbi példához hasonlóan tehető meg. Első körben létrehozzuk a szabályt:

A szabálynak mindig 4 paramétere van, ebből számunkra az első kettő az igazán fontos.

${browser} : Referencia a WebDriver példányhoz (Ennek az értékére csak ritkán van szükség.)

${strategy} : Lokátor stratégia neve. Valójában ez az a paraméter, amit használni fogunk. A legtöbb esetben ebben a paraméterben adjuk át a label értékét. (Lásd később.)

A szabály visszatérési értéke mindig egy web-element. Ha nem javascriptezünk, akkor számunkra a legegyszerűbb módszer a „Get WebElements” kulcsszó használata lesz.

Mielőtt használjuk a szabályt, amit létrehoztunk, mindenképpen regisztrálnunk kell az Add Location Strategy kulcsszóval:

Ezután már használható a saját lokátort, valahogy így:

A sor hatására megkeresi azt az elemet, aminek az ID-ja „Valamilyen érték”-et tartalmazz és ráklikkel. 

A stratégiánk az lesz, hogy létrehozunk ez alapján egyedi lokátor típusokat (szabályokat), majd ezeket a tesztesetek végrehajtása előtt egyetlen kulcsszó használatával hozzáadjuk az alap lokátor típusokhoz. Innentől a saját lokátor típusainkat tudjuk használni.

A tesztesetet tartalmazó file a regisztracio_din_sel.robot lesz, és az egyedi lokátorokat tartalmazó file pedig a locator.robot lesz.

A beviteli adatokat egy YAML állományból olvassuk ki és változókként hivatkozhatunk majd rájuk.

LANDING PAGE

A főoldalon nem sok dolgunk van. A header-ben találunk egy linket, ami átdob az AUTHENTICATION oldalra.

HTML struktúra:

Dinamikus selector meghatározása:

Mivel a header dobozban kvázi csak linkek vannak, ráadásul egyik sem szerepel ugyanazon névvel, egyszerűen megtalálhatók a nevük szerint.

Ha megnézzük az xpath felépítését, láthatjuk, hogy a header container alatt található összes linkre szűrünk, amelynek szövege a ${locator} paraméterben megadottal egyezik. A tesztesetünkben a paraméterünk a ’Sign in’ lesz.

Adjuk hozzá a szabályt a test suit-nak!

A locator működéséhez előbb „Add locators” kulcsszóval hozzáadjuk a stratégiát egyedi selector-ként az alábbi sorral:

A fenti sor használata után a szabályunkra LOC_header néven hivatkozhatunk.

A tesztesetet tartalmazó regisztracio_din_sel.robot-ban létrehozzuk az új lokátortípust használó „Headerben kattintás” kulcsszót:

Mivel létrehoztuk az egyedi lokátorunkat „LOC_header” névvel, így az paraméterben meg fogja kapni a ${nev} változót, ami esetünkben a ’Sign in’ érték lesz. Ezt a Locator Header kulcsszó behelyettesíti az xpath-be, a megadott helyre, lefut a SeleniumLibrary.Get WebElement függvény, ami megkeresi a megfelelő objektumot, majd elmenti a ${element} változóba, amit egyből vissza is ad az interakció elvégzéséhez.

Ezek után egy Test case-ben így lehet a Sign in-ra kattintani:

Figyeljük meg: A Locator Header Keyword több argumentummal is rendelkezik. Ezek közül nekünk csak a ${locator} lényeges. Ez tartalmazza azt az értéket, amit mi a „:” után megadunk. (Futásidőben a többi változó is kap értéket, de ezekkel ebben a cikkben nem foglalkozunk.)

Mivel a lokátor összekötése a teszt kulcsszóval ugyanígy működik minden elemnél, ezért a továbbiakban csak a lényegi részekkel foglalkozunk a trükkösebb típusoknál.

AUTHENTICATION

Itt ki kell töltenünk egy email címet és meg kell nyomnunk egy gombot.

HTML struktúra:

Dinamikus selector meghatározása:

A fenti lokátor meghatározás trükkje az, hogy lehetőséget biztosítunk szekció megadására is, de nem tesszük kötelezővé, hogy ezt megadja a felhasználó. Tehát ha a képernyőn egy label alapján be lehet azonosítani egy szövegmezőt, akkor ezt megtehetjük, de ha a mezőazonosításhoz szükséges, megadhatjuk a szekciót is szekció;label formában.

Magyarázat:

  • Split String egy szövegből listát készít. A szövegben, a listaelem-határoló esetünkben a ; jel. Ha nincs ; jel, akkor a lista egyelemű lesz, különben kettő.
  • A Get Length lekérdezi egy lista elemszámát
  • A „Run Keyword iffeltételkulcsszó1ELSEkulcsszó2” megvizsgálja a feltételt, esetünkben, hogy a lista kisebb-e két elemnél, és ha igaz, akkor kulcsszó1-et, ha nem igaz, akkor kulcsszó2-t hajtja végre.
  • A listák első elemének indexe a Robot Frameworkben 0. Pl.: @{element_parameterek}[0]

Még egy „trükköt” tartalmaz a szabályunk. A szabály jó text és textarea típusú input-mezőkre is (… //*[self::input or self::textarea]).

Button esetén sokkal könnyebb a helyzet, trükközni sem kell. Az előzőek alapján könnyen összerakható.

CREATE AN ACCOUNT

Utolsó oldalunk jócskán ellát minket kitölteni valóval, hisz itt történik a regisztráció lényegi része. Azt azonban már most felfedezhetjük, hogy a nagy részük szöveges mező, amihez már tökéletes az általunk eddig létrehozott lokátor. Nézzük, ami még nem volt, és érdemes róla szót ejteni!

HTML struktúra:

Rádiógombszabály meghatározása:

Rádiógomb választásnál annyi a trükk, hogy itt közvetlenül az értéknek megfelelő inputra kell kattintani. Tehát a ${locator} paraméter nem csak labeleket, hanem a kiválasztani kívánt értéket is (!) tartalmazza, és azon pedig már csak egy klikk parancsra van szükség. Példák a ${locator} paraméterre:

  • YOUR PERSONAL INFORMATION;Title;Mrs.
  • Title;Mrs.

A lista és a dátumlisták szabálya:

A „sima” Select-nél ugyanahhoz a labelhez egyetlen legördülő tartozik, a SelectDate-nél három is. Mivel a dátum választás specifikus eset szokott lenni, és valószínűleg ugyanúgy van megoldva mindenhol az oldalon, semmilyen problémát nem fog okozni, hogy külön lokátor típust készítünk. Természetesen a lokátorban meg kell adni, hogy a választólisták közül melyikre gondolok. Ezt pedig az eddig is használt ’;’-vel oldható meg. Mint az eddigieknél, itt is felkészültem szekcióneves és nem szekcióneves paraméter megadásra. Példák ${locator} megadásra:

  • YOUR PERSONAL INFORMATION; Date of Birth; days
  • Date of Birth; months
  • Date of Birth; years

A teljes kód természetesen letölthető az ITT jelölt elérhetőségen, Webshop_test névvel.

Még néhány gondolat:

Ha megfigyeljük a létrehozott lokátorokat, akkor felfedezhetünk bennük gyakran ismétlődő elemeket. Ilyen például a h3 meghatározáshoz használt xpath részlet, vagy a label meghatározáshoz használt részlet. Ezeket könnyedén kicserélhetnénk GET-es függvényekre, amik visszaadják nekünk a paraméterben megadott objektum xpath elérhetőségét, és ezekből a visszakapott részletekből állítanánk össze a végleges selector-t. Ez egy következő szabályalkotás szint, amit mindenképp érdemes megcsinálni. Ezen a szinten lényegében az oldalak felépítési szabályait alkothatjuk meg.  

A teszteset, amit futtatunk valójában nem túl szép. Csak egyetlen helyen tartalmaz ellenőrzést, nem foglalkozik a jelölőnégyzetekkel, a teszteset nem túl szofisztikált. A szép teszteset írás kritériumaira, a megfelelő struktúra kialakítására külön cikkeket lehetne szánni. Remélhetőleg e magazin hasábjain lesz még ezekről is szó.

Befejezés

Ha már így a végére értünk a bemutatónak, álljunk meg egy kis összevetés erejéig:

Page Object Model által szükséges lokátorok száma: 26 db

Dinamikus selectorok szerinti darabszám: 6 db

Tehát míg az előbbi módszerrel 26 db útvonalat kell karbantartanunk, utóbbival csak 6-ot.
Továbbá van egy plusz légy is, amit már lecsaptunk a dinamikus légycsapónkkal, mégpedig, hogy a Contact Us folyamat is végigvihető (leszámítva a nem kötelező file feltöltést) az általunk már eddig létrehozott lokátor típusokkal.

Természetesen nem állítható, hogy ez egy univerzális módszer mindenre. Ez semmiről sem mondható el az automatizálás világában. Vannak helyzetek, amikor egyéb megoldások sokkal jobban megfelelnek a célra, így eme technika hatékonyságát mindenki döntse el a cikk, illetve saját tapasztalatai alapján. Köszönöm a figyelmét mindenkinek, aki olvasta a bemutatót, és remélem sikerült felkeltenem a kíváncsiságot egy rövid és kötetlen kísérletezéshez!

A szerző

Őri Róbert
Őri Róbert
Őri Róbert vagyok, szoftver tesztelőként dolgozom lassan 10 éve a Passed Informatikai Kft.-nél, főleg telekommunikációs és banki területen. Mivel mindig is motivált a manuális munkavégzés automatizációval való támogatása, illetve hatékonyabbá tétele, így autodidakta módon kezdtem el ismerkedni a programozással, majd később néhány képzés elvégzése után áteveztem az automatizált tesztelés területére, ahol jelenleg is vagyok. A kreatív énemet a munka mellett egy otthoni mobil applikációs projekt megalkotásában élem ki, amely már szerencsére befejezés alatt áll, így helyet adva más ötletek megvalósításának.
Vissza