Hol is kezdjem? Ma is elégettem nem kevés tokent, bár szerencsére ezek ingyen vannak/voltak. Amit ki akartam próbálni, hogy telepítettem egy Rider-t, ami egy IDE, és nekem a .net miatt van rá szükség, majd pedig a Copilot-tal és Gemini-vel elkezdtem ebből egy Playwright, Nunit és .net projectet faragni. Aztán jött a szokásos nehézség, kell egy jelentést generáló eszköz, ami többet vagy épp másképpen tud, mint az Allure. Az AI azt mondta, hogy Report Portal.
Nem volt mit tenni, elkezdtem belefaragni ezt, és az API kulcs generáláson kívül minden lépést az AI CLI-on keresztül csináltam meg. Szerintem elég pofás lett a végeredmény, de majd erről egy másik bejegyzésben írok részletesebben.
Most inkább megmutatom, hogy mit tud a Report Portal.
Mit mond a Gemini?
A ReportPortal egy nyílt forráskódú (Open Source), AI-alapú tesztriportáló és analitikai platform. Elsősorban automatizált tesztek eredményeinek gyűjtésére, vizualizálására és elemzésére szolgál.
Főbb jellemzők és előnyök
Központi dashboard: Egységes felületen gyűjti össze a különböző tesztkeretrendszerekből és CI/CD csatornákból származó teszteredményeket.
AI / Machine Learning alapú hibaelemzés: A korábbi futtatások alapján automatikusan felcímkézi a hibákat (pl. termékhiba, teszthiba, infrastruktúra-probléma), így drasztikusan csökkenti a manuális triázsolásra fordított időt.
Valós idejű analitika: A tesztek futása közben élőben láthatók az eredmények, trendek és statisztikák.
Integrációk: Szorosan együttműködik hibakövető rendszerekkel (Jira, Rally, Redmine) és CI/CD eszközökkel (Jenkins, GitLab CI, GitHub Actions).
A ReportPortal architektúrája
A ReportPortal mikroszolgáltatás-alapú architektúrát használ, amely több konténerből áll (API Service, UI, Index Service/AI Engine, PostgreSQL, RabbitMQ, OpenSearch/Elasticsearch). Ezért a legegyszerűbb és legajánlottabb módja a lokális futtatásnak a Docker / Docker Compose.
Mire jó az AI? Hát például arra, hogy ha írni szeretnék egy témáról, de lusta vagyok, az egyébként is Google segítsével összeszedett információkat rendszerbe szedni, akkor relatív gyorsan kézhez kapok egy bejegyzést.
A Page Object Model (POM) a szoftvertesztelés-automatizálás egyik legnépszerűbb és leghatékonyabb tervezési mintája (Design Pattern). A lényege, hogy az alkalmazás egyes weboldalait (vagy oldalrészeit) különálló objektumokként képezi le a kód szintjén.
Miért érdemes használni?
Karbantarthatóság: Ha megváltozik egy gomb ID-ja vagy egy mező elhelyezkedése, elegendő azt egyetlen helyen (a Page Object osztályban) átírni, a teszteseteket nem kell bántani.
Kód újrafelhasználhatósága: A gyakori műveletek (pl. bejelentkezés, keresés) egyszer vannak megírva, és bármelyik tesztből meghívhatók.
Olvashatóság: A tesztkód tiszta, átlátható és üzleti logikát követő lesz, rejtve a techniai megvalósítást (pl. DOM-lekérdezéseket).
Minta megvalósítás (Python + Selenium)
Az alábbiakban egy klasszikus bejelentkezési folyamat példáján keresztül látható a POM működése.
A Page Object osztály (login_page.py)
Ez az osztály tartalmazza az oldal elemeinek azonosítóit (lokátorait) és a végezhető műveleteket.
Python
from selenium.webdriver.common.by import ByclassLoginPage:def__init__(self,driver):self.driver = driver# Lokátorok (különválasztva a logikától)self._username_input =(By.ID,"username")self._password_input =(By.ID,"password")self._login_button =(By.CSS_SELECTOR,"button[type='submit']")self._error_message =(By.CLASS_NAME,"flash-error")# Akciók / Műveletekdefenter_username(self,username:str):self.driver.find_element(*self._username_input).send_keys(username)defenter_password(self,password:str):self.driver.find_element(*self._password_input).send_keys(password)defclick_login(self):self.driver.find_element(*self._login_button).click()# Összetett folyamat (Láncolt / Magasabb szintű akció)deflogin(self,username:str,password:str):self.enter_username(username)self.enter_password(password)self.click_login()defget_error_message(self)->str:returnself.driver.find_element(*self._error_message).text
A Teszteset (test_login.py)
A tesztkód csak a Page Object által nyújtott metódusokat használja, így végtelenül egyszerű és olvasható.
Ne tegyél assertion-öket a Page Object-be: A assert kifejezések a tesztfájlban maradjanak, a Page Object csak adatot adjon vissza vagy állapotot módosítson.
Page Factory használata: Bizonyos keretrendszerekben (pl. Java + Selenium) a @FindBy annotációkkal még tisztább szerkezet érhető el.
Lazy loading: Az elemeket csak akkor kérd le a DOM-ból, amikor ténylegesen szükség van rájuk (például dinamikus felületek esetén).
A Page Object Model (POM) megvalósítása a modernebb eszközökkel (mint a Playwright vagy a Selenium Java-alapú változata) még letisztultabbá válik, mivel ezek a keretrendszerek beépített architektúrával támogatják a megbízhatóbb elemkezelést.
Az alábbiakban mindkét megközelítésre találsz egy-egy komplett kódmintát.
Playwright + TypeScript (Ajánlott / Modern megközelítés)
A Playwright eleve magában foglalja az automatikus várakozást (Auto-waiting), így nincs szükség explicit wait-ek kézi kezelésére.
A Page Object osztály (pages/LoginPage.ts)
TypeScript
import {Page,Locator} from '@playwright/test';exportclassLoginPage{readonlypage:Page;readonlyusernameInput:Locator;readonlypasswordInput:Locator;readonlyloginButton:Locator;readonlyerrorMessage:Locator;constructor(page:Page){self.page=page;// A Playwright-ban a lokátorok deklaratívak, nem kérdezik le azonnal a DOM-otthis.usernameInput=page.locator('#username');this.passwordInput=page.locator('#password');this.loginButton=page.locator('button[type="submit"]');this.errorMessage=page.locator('.flash-error');}asyncgoto(){awaitthis.page.goto('https://example.com/login');}asynclogin(username:string,password:string){awaitthis.usernameInput.fill(username);awaitthis.passwordInput.fill(password);awaitthis.loginButton.click();}asyncgetErrorMessage():Promise<string>{returnawaitthis.errorMessage.textContent() ||'';}}
A Tesztfájl (tests/login.spec.ts)
TypeScript
import {test,expect} from '@playwright/test';import {LoginPage} from '../pages/LoginPage';test.describe('Bejelentkezés tesztek',()=>{letloginPage:LoginPage;test.beforeEach(async({page})=>{loginPage=newLoginPage(page);awaitloginPage.goto();});test('Sikeres bejelentkezés',async({page})=>{awaitloginPage.login('valid_user','correct_password');// Ellenőrzés Playwright assert-telawaitexpect(page).toHaveURL('https://example.com/dashboard');});test('Hibás bejelentkezés',async()=>{awaitloginPage.login('invalid_user','wrong_password');awaitexpect(loginPage.errorMessage).toBeVisible();awaitexpect(loginPage.errorMessage).toContainText('Érvénytelen adatok');});});
Java + Selenium (Klasszikus keretrendszer)
Java környezetben a PageFactory és a @FindBy annotációk használata a legelterjedtebb POM minta.
A @FindBy elemek lekezeléséhez várakozás (WebDriverWait) kellhet
Párhuzamosítás
Alapból támogatott a tesztfutztatóban
TestNG vagy JUnit szálkezelést igényel
Inicializálás
Egyszerű objektumkonstruktor
PageFactory.initElements() hívás szükséges
A Playwright Custom Fixture funkciója segítségével a Page Object osztályok példányosítását teljesen kiszervezheted a tesztekből. Ezzel elkerülhető, hogy minden egyes tesztfájlban manuálisan kelljen megadni a const loginPage = new LoginPage(page) sorokat.
A tesztek így közvetlenül paraméterként kérhetik el a szükséges oldalobjektumokat, az infrastruktúra pedig automatikusan példányosítja és előkészíti azokat.
A Page Object osztályok (pages/)
A megszokott módon hozzuk létre az oldalklasszokat.
TypeScript
// pages/LoginPage.tsimport {Page,Locator} from '@playwright/test';exportclassLoginPage{readonlypage:Page;readonlyusernameInput:Locator;constructor(page:Page){this.page=page;this.usernameInput=page.locator('#username');}asyncgoto(){awaitthis.page.goto('/login');}}// pages/DashboardPage.tsimport {Page,Locator} from '@playwright/test';exportclassDashboardPage{readonlypage:Page;readonlyuserMenu:Locator;constructor(page:Page){this.page=page;this.userMenu=page.locator('#user-menu');}}
A Custom Fixture létrehozása (fixtures/baseTest.ts)
Itt terjesztjük ki a Playwright alapértelmezett test objektumát, megadva a saját Page Object fixture-jeinket.
TypeScript
import {test as base} from '@playwright/test';import {LoginPage} from '../pages/LoginPage';import {DashboardPage} from '../pages/DashboardPage';// 1. Típusdefiníció a fixture-ökhöztypeMyFixtures={loginPage:LoginPage;dashboardPage:DashboardPage;};// 2. A 'base.extend' használatával regisztráljuk a saját fixture-jeinketexportconsttest=base.extend<MyFixtures>({// Automatikusan példányosítja a LoginPage-t és igény esetén megnyitja az oldaltloginPage:async({page},use)=>{constloginPage=newLoginPage(page);awaitloginPage.goto();// Akár előkészítő lépéseket is tehetünk ideawaituse(loginPage);// Átadja az objektumot a tesztnek},// Példányosítja a DashboardPage-tdashboardPage:async({page},use)=>{constdashboardPage=newDashboardPage(page);awaituse(dashboardPage);},});// Az 'expect'-et is exportáljuk a kényelmes importálásértexport {expect} from '@playwright/test';
A Fixture-ök használata a tesztekben (tests/login.spec.ts)
A @playwright/test helyett a saját fixtures/baseTest fájlunkból importáljuk a test objektumot. A tesztfüggvény paramétereként megadott nevek alapján a Playwright automatikusan beadagolja a megfelelő példányokat.
TypeScript
// Figyelem: A saját kiterjesztett test objektumunkat importáljuk!import {test,expect} from '../fixtures/baseTest';test('Sikeres bejelentkezés custom fixture-rel',async({loginPage,dashboardPage})=>{// A loginPage.goto() már lefutott a fixture-ben!awaitloginPage.usernameInput.fill('standard_user');// A dashboardPage is azonnal használható, nem kellett 'new'-val példányosítaniawaitexpect(dashboardPage.userMenu).toBeVisible();});
Miért ez a legnépszerűbb Playwright architektúra?
Nulla boilerplate kód: Nem kell beforeEach blokkokban példányosítani az osztályokat.
Lazy loading (Lusta betöltés): Csak azok a Page Object-ek példányosulnak, amiket a teszt fejlécében ({ loginPage, dashboardPage }) kifejezetten elkérsz.
Beépített tear-down: A fixture-ben a use() hívás utáni kódrészlet automatikusan lefut a teszt végén (takarításra, kijelentkezésre ideális).