Címke: Java

A Java egy magas szintű, objektumorientált és osztályalapú programozási nyelv, amelyet a „Write Once, Run Anywhere” (Írd meg egyszer, futtasd bárhol) elv alapján terveztek. Ez azt jelenti, hogy a lefordított Java kód minden olyan platformon futtatható, amely támogatja a Java Virtual Machine (JVM) környezetet, anélkül, hogy újra kellene fordítani.

https://www.java.com/en/

  • Készítsünk Playwright project-et Copilot-tal

    Készítsünk Playwright project-et Copilot-tal

    Megkésve, de törve nem, én is elkezdtem egyre több dologra használni az AI-t, ahogy az a korábbi bejegyzéseimből is látszik. Reggel gondoltam egy merészet, és megkértem a Copilot-ot, hogy kezdjünk el csinálni egy Playwright, TypeScript projectet, mindezt VSCode-ban, és csak CLI-jal. Meg kell mondjam, egész jól sikerültek az alapok, és időben is lényegesen hamarabb készült el, mintsem, ha kézzel kezdem el.

    Felbuzdulva ezen, megkértem, hogy integrálja bele az Allure riport készítést, ami elsőre nem volt teljes siker, mert nem tartalmazta a korábbi futásokat a kérésem ellenére, de ez is hamar javítva lett.

    Folytattam azzal, hogy egy ingyenes és publikus API hívásra írattam vele 3 tesztet, majd pedig kértem, hogy legyen 2 negatív is, amit ő elsőre úgy értett, hogy átírta a meglévőket. Ezt is hamar javítottuk.

    Kértem, hogy amit csináltunk, azt tegye bele egy Word fájlba, illetve még készítettem vele egy readme.md fájlt is. Szerintem egész jól sikerült, mindezt relatív kevés idő alatt, szóval biztosan fogom még folytatni vele a munkát.

    Íme a teljes lista:

    Project path: D:\Repositories\ai-playwright
    Earliest retrievable project record:
    approximately 08:55 local time (06:55 UTC)

    08:53 ? Initial workspace session

    • Opened the working area under D:\Repositories.

    08:55 ? Created the Playwright project

    • Created D:\Repositories\ai-playwright as a TypeScript Playwright project.
    • Configured Chromium, added example tests and a GitHub Actions workflow.
    • Installed dependencies and Chromium.
    • Verified that the two starter tests passed with npx playwright test.

    09:01 ? Changed reporting to Allure

    • Switched the default Playwright reporter to Allure.
    • Added Allure report generation and execution-history persistence.
    • Updated package.json, playwright.config.ts, .github/workflows/playwright.yml, .gitignore, and scripts/allure-history.js.
    • Configured CI to restore and save Allure history.
    • Verified the initial tests and report generation.

    09:07?09:23 ? Opened and fixed Allure history

    • Generated allure-report and started it with npm run allure:open.
    • Investigated why previous executions were not visible.
    • Fixed the issue by clearing old result files before each run while preserving history.
    • Verified that the report showed three executions per test instead of treating earlier executions as retries.

    09:26 ? Added Open-Meteo API tests

    • Added tests in tests/open-meteo-api.spec.ts.
    • Covered a valid forecast request, invalid latitude, and invalid longitude.
    • All three tests passed.

    09:28?09:34 ? Regenerated the report and improved assertions

    • Regenerated Allure with the API tests.
    • Added descriptive failure messages to the expect assertions.

    09:49?09:51 ? Added more negative API scenarios

    • Added a request missing required longitude.
    • Added a request with an unsupported current-weather variable.
    • The API test file reached five tests total.

    09:52 ? Verified all tests

    • Ran the full suite.
    • All seven tests passed.
    • Regenerated the Allure report with all tests.

    09:55?10:03 ? Fixed Allure generation in GitHub Actions

    • Investigated why the report was not generated in CI.
    • Updated the workflow to restore history, run Playwright, always generate the report, and upload the report artifact when possible.
    • Local verification passed.

    10:07?10:12 ? Discussed opening reports from CI

    • Clarified that GitHub Actions cannot directly open a browser on the runner.
    • Discussed GitHub Pages as the way to automatically host and view the report.
    • Explained how to open a downloaded report locally with npx allure open.

    10:20 ? Opened the Allure report again

    10:31 ? Added Playwright Codegen

    • Added the codegen script to package.json.
    • Usage: npm run codegen — https://example.com.
    • Discussed saving recorded tests with –output tests/recorded.spec.ts.

    10:34?10:48 ? Reviewed the project and exported coverage

    • Explained that the project is a Playwright test project, not the application under test.
    • Identified that baseURL and webServer are not configured.
    • Created D:\Repositories\ai-playwright\test-coverage.xlsx.
    • The workbook contains all seven test cases, behaviors, assertions, Allure statuses, and a test-scope coverage summary.

    Note: The earliest project-creation record available is the summarized 08:55 local-time session; the initial setup session does not contain a complete message-by-message transcript.

    10:56 – Added project README documentation

    • Created README.md in the project root.
    • Documented prerequisites and installation from scratch.
    • Documented browser and API test execution.
    • Documented Allure report generation, opening, and execution-history handling.
    • Documented Playwright Codegen usage.
    • Documented project configuration, structure, GitHub Actions CI behavior, and troubleshooting.
  • POM avagy Page Object Model

    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 By
    
    class LoginPage:
        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űveletek
        def enter_username(self, username: str):
            self.driver.find_element(*self._username_input).send_keys(username)
    
        def enter_password(self, password: str):
            self.driver.find_element(*self._password_input).send_keys(password)
    
        def click_login(self):
            self.driver.find_element(*self._login_button).click()
    
        # Összetett folyamat (Láncolt / Magasabb szintű akció)
        def login(self, username: str, password: str):
            self.enter_username(username)
            self.enter_password(password)
            self.click_login()
    
        def get_error_message(self) -> str:
            return self.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ó.

    Python

    import pytest
    from selenium import webdriver
    from login_page import LoginPage
    
    @pytest.fixture
    def driver():
        driver = webdriver.Chrome()
        driver.get("https://example.com/login")
        yield driver
        driver.quit()
    
    def test_successful_login(driver):
        login_page = LoginPage(driver)
        
        # Bejelentkezés végrehajtása
        login_page.login("valid_user", "correct_password")
        
        # Ellenőrzés (Assertion)
        assert driver.current_url == "https://example.com/dashboard"
    
    def test_failed_login(driver):
        login_page = LoginPage(driver)
        
        login_page.login("invalid_user", "wrong_password")
        
        # Hibaüzenet ellenőrzése
        assert "Érvénytelen adatok" in login_page.get_error_message()
    

    Jó tanácsok a gyakorlati alkalmazáshoz

    • 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';
    
    export class LoginPage {
      readonly page: Page;
      readonly usernameInput: Locator;
      readonly passwordInput: Locator;
      readonly loginButton: Locator;
      readonly errorMessage: Locator;
    
      constructor(page: Page) {
        self.page = page;
        // A Playwright-ban a lokátorok deklaratívak, nem kérdezik le azonnal a DOM-ot
        this.usernameInput = page.locator('#username');
        this.passwordInput = page.locator('#password');
        this.loginButton = page.locator('button[type="submit"]');
        this.errorMessage = page.locator('.flash-error');
      }
    
      async goto() {
        await this.page.goto('https://example.com/login');
      }
    
      async login(username: string, password: string) {
        await this.usernameInput.fill(username);
        await this.passwordInput.fill(password);
        await this.loginButton.click();
      }
    
      async getErrorMessage(): Promise<string> {
        return await this.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', () => {
      let loginPage: LoginPage;
    
      test.beforeEach(async ({ page }) => {
        loginPage = new LoginPage(page);
        await loginPage.goto();
      });
    
      test('Sikeres bejelentkezés', async ({ page }) => {
        await loginPage.login('valid_user', 'correct_password');
        
        // Ellenőrzés Playwright assert-tel
        await expect(page).toHaveURL('https://example.com/dashboard');
      });
    
      test('Hibás bejelentkezés', async () => {
        await loginPage.login('invalid_user', 'wrong_password');
        
        await expect(loginPage.errorMessage).toBeVisible();
        await expect(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 Page Object osztály (LoginPage.java)

    Java

    package pages;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.support.FindBy;
    import org.openqa.selenium.support.PageFactory;
    
    public class LoginPage {
        private WebDriver driver;
    
        // Lokátorok deklarálása annotációkkal
        @FindBy(id = "username")
        private WebElement usernameInput;
    
        @FindBy(id = "password")
        private WebElement passwordInput;
    
        @FindBy(css = "button[type='submit']")
        private WebElement loginButton;
    
        @FindBy(className = "flash-error")
        private WebElement errorMessage;
    
        // Konstruktor: inicializálja a PageFactory elemeit
        public LoginPage(WebDriver driver) {
            this.driver = driver;
            PageFactory.initElements(driver, this);
        }
    
        public void enterUsername(String username) {
            usernameInput.clear();
            usernameInput.sendKeys(username);
        }
    
        public void enterPassword(String password) {
            passwordInput.clear();
            passwordInput.sendKeys(password);
        }
    
        public void clickLogin() {
            loginButton.click();
        }
    
        public void login(String username, String password) {
            enterUsername(username);
            enterPassword(password);
            clickLogin();
        }
    
        public String getErrorMessageText() {
            return errorMessage.getText();
        }
    }
    

    A Tesztosztály (JUnit 5 használatával) (LoginTest.java)

    Java

    package tests;
    
    import org.junit.jupiter.api.AfterEach;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import pages.LoginPage;
    
    import static org.junit.jupiter.api.Assertions.assertEquals;
    import static org.junit.jupiter.api.Assertions.assertTrue;
    
    public class LoginTest {
        private WebDriver driver;
        private LoginPage loginPage;
    
        @BeforeEach
        public void setUp() {
            driver = new ChromeDriver();
            driver.manage().window().maximize();
            driver.get("https://example.com/login");
            loginPage = new LoginPage(driver);
        }
    
        @Test
        public void testSuccessfulLogin() {
            loginPage.login("valid_user", "correct_password");
            assertEquals("https://example.com/dashboard", driver.getCurrentUrl());
        }
    
        @Test
        public void testFailedLogin() {
            loginPage.login("invalid_user", "wrong_password");
            assertTrue(loginPage.getErrorMessageText().contains("Érvénytelen adatok"));
        }
    
        @AfterEach
        public void tearDown() {
            if (driver != null) {
                driver.quit();
            }
        }
    }
    

    Főbb különbségek a két megközelítés között

    SzempontPlaywright (TypeScript)Selenium (Java)
    LokátorokA Locator objektumok deklaratívak (auto-wait)A @FindBy elemek lekezeléséhez várakozás (WebDriverWait) kellhet
    PárhuzamosításAlapból támogatott a tesztfutztatóbanTestNG vagy JUnit szálkezelést igényel
    InicializálásEgyszerű objektumkonstruktorPageFactory.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.ts
    import { Page, Locator } from '@playwright/test';
    
    export class LoginPage {
      readonly page: Page;
      readonly usernameInput: Locator;
    
      constructor(page: Page) {
        this.page = page;
        this.usernameInput = page.locator('#username');
      }
    
      async goto() {
        await this.page.goto('/login');
      }
    }
    
    // pages/DashboardPage.ts
    import { Page, Locator } from '@playwright/test';
    
    export class DashboardPage {
      readonly page: Page;
      readonly userMenu: 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öz
    type MyFixtures = {
      loginPage: LoginPage;
      dashboardPage: DashboardPage;
    };
    
    // 2. A 'base.extend' használatával regisztráljuk a saját fixture-jeinket
    export const test = base.extend<MyFixtures>({
      // Automatikusan példányosítja a LoginPage-t és igény esetén megnyitja az oldalt
      loginPage: async ({ page }, use) => {
        const loginPage = new LoginPage(page);
        await loginPage.goto(); // Akár előkészítő lépéseket is tehetünk ide
        await use(loginPage);   // Átadja az objektumot a tesztnek
      },
    
      // Példányosítja a DashboardPage-t
      dashboardPage: async ({ page }, use) => {
        const dashboardPage = new DashboardPage(page);
        await use(dashboardPage);
      },
    });
    
    // Az 'expect'-et is exportáljuk a kényelmes importálásért
    export { 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!
      await loginPage.usernameInput.fill('standard_user');
      
      // A dashboardPage is azonnal használható, nem kellett 'new'-val példányosítani
      await expect(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).
  • JAVA method overloading vs overriding

    Ez a két, vagy inkább egyként feltett kérdés szinte minden technikai interjú kapcsán előkerül. Miért? Mert nagyon hasznos tud lenni, és átláthatóbb kódot lehet így írni. Na de nézzük meg, hogy mik is ezek! Illetve inkább idézek a saját szavaim helyett, mert nem biztos, hogy ennyire pontosan meg tudnám fogalmazni a definícióját.

    Method overloading

    Javában a metódusok túlterhelése lehetővé teszi a fejlesztők számára, hogy több metódust definiáljanak ugyanazzal a névvel, de különböző paraméterekkel. Ez a rugalmasság olvashatóbbá és adaptívabbá teszi a kódot, mivel egy metódus különböző variációi különböző argumentumtípusokat vagy -mennyiségeket kezelhetnek. Azonban annak megértése, hogy a Java hogyan választja ki, hogy melyik metódust hívja meg, elengedhetetlen a hibamentes kód írásához.

    Egyszerű példa kód

    class Calculator {
        void add(int a, int b) {
            System.out.println("add(int, int) called: " + (a + b));
        }
    
        void add(double a, double b) {
            System.out.println("add(double, double) called: " + (a + b));
        }
    }

    Mi is történik a fenti példában? Két metódusnak ugyanaz a neve, de a bemenő paraméterinek a típusa különböző, így tehát az lesz használva, ahol egyeznek a paraméterek. Automatizálás során például egy jó példa lehet, ha a metódus integert vagy stringet tud fogadni, és annak megfelelően végrehajtani mondjuk egy kiválasztást. Ilyenkor ugye a bemenő paraméter típusa fogja meghatározni, hogy melyik függvény fut le, és mindkét függvény ugyanarra a névre hallgat.

    Method overriding

    A metódusok felülírása az objektumorientált programozás (OOP) alapvető koncepciója, amely lehetővé teszi egy alosztály számára, hogy egy olyan metódus specifikus implementációját biztosítsa, amely már definiálva van a szuperosztályában. Kulcsfontosságú szerepet játszik a futásidejű polimorfizmus elérésében Java-ban.

    • Öröklődés: A metódusok felülírása csak öröklődés esetén történik, ami azt jelenti, hogy egy alosztály örökli a metódusokat és tulajdonságokat egy szuperosztálytól.
    • Ugyanazon metódus szignatúra: Ahhoz, hogy a metódusok felülírása megtörténjen, az alosztályban lévő metódusnak ugyanazzal a névvel, visszatérési típussal és paraméterekkel kell rendelkeznie, mint a szuperosztályban lévő metódusnak.
    • Felülírás vs. túlterhelés: A metódusok felülírását nem szabad összekeverni a metódusok túlterhelésével. A túlterhelés azt jelenti, hogy több metódusnak ugyanaz a neve, de paramétereik különböznek, míg a felülírás az alosztályban lévő metódus újradefiniálását jelenti ugyanazzal a szignatúrával.

    Egyszerű példa kód

    class Animal {
        void sound() {
            System.out.println("This animal makes a sound");
        }
    }
    
    class Dog extends Animal {
        @Override
        void sound() {
            System.out.println("The dog barks");
        }
    }

    Miért érdemes metódusfelülírást használni?

    • Polimorfizmus: A metódusfelülírás lehetővé teszi egy alosztály számára, hogy egy adott metódushoz egy adott implementációt biztosítson, lehetővé téve a polimorfizmust. Ez azt jelenti, hogy ugyanaz a metódushívás eltérően viselkedhet attól függően, hogy melyik objektum hívja meg. Például mind az Animal, mind a Dog objektum meghívhatja a sound() metódust, de az eredmény az objektum típusától függ.
    • Dinamikus metódusküldés: Futásidőben a végrehajtandó metódust az objektum típusa határozza meg, nem a hivatkozás típusa. Ezt a folyamatot dinamikus metódusküldésnek vagy futásidejű polimorfizmusnak nevezik.
    • Újrafelhasználhatóság és bővíthetőség: A felülírás lehetővé teszi az örökölt metódusok viselkedésének kiterjesztését vagy módosítását. Ez elősegíti a kód újrafelhasználását, mivel az alosztály örökölheti a közös viselkedést, miközben további funkciókat biztosít, vagy szükség szerint felülírja a viselkedést.
    class Animal {
        void sound() {
            System.out.println("This animal makes a sound");
        }
    }
    
    class Dog extends Animal {
        @Override
        void sound() {
            super.sound();  // Calls the superclass method
            System.out.println("The dog barks");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Dog myDog = new Dog();
            myDog.sound();  // Calls the overridden method
        }
    }

    Metódus felülírásának szabályai

    • A metódusnak ugyanazzal a szignatúrával kell rendelkeznie, mint a szuperosztályban.
    • A metódusnak az eredeti metódust tartalmazó osztály alosztályában kell lennie.
    • Az alosztályban lévő metódusnak ugyanolyan vagy könnyebben hozzáférhető hozzáférési módosítóval kell rendelkeznie. Például, ha egy metódus védett a szuperosztályban, akkor nem lehet privát az alosztályban.
    • Nem írhatjuk felül a final, static vagy private metódusokat.

    Szeretem a Medium leírásait, számomra mindig is könnyen érhető, és nagyon sok témát dolgoznak fel. Csak ajánlani tudom!

  • Automatizáló framework-ök a szakmám során

    Eddigi pályafutásom során jó pár framework-höz volt szerencsém különféle programnyelvek mellett, és hát azt kell mondanom, hogy ideje ezeket összegyűjtenem, mert kezdem egy részét elfelejteni.

    • Selenium WebDriver (#C, JAVA)
    • HP UFT (Visual Basic Script)
    • Katalon Studio (Kotlin)
    • Cypress (JavaScript)
    • Playwright (TypeScript)

    Selenium + C# + NUnit

    Kezdjünk is bele. Szóval még az automatizáló pályám elején volt lehetőségem a munkám mellett gyakorolni, és az épp aktuális Selenium volt a választott C#-pal. Ez akkoriban azt jelentette, hogy ahogy ma egy demó kód kinéz, kb úgy írtam én is meg Visual Studioban, majd pedig NUnitban a saját gépemről futottak a tesztek. Attól függetlenül, hogy messze volt egy professziónális megoldástól, szépen fogta a regressziós hibákat.

    Valahogy így kell elképzelni, ahogy a tesztek futottak.

    HP UFT + Visual Basic Script + HP ALM

    Ez volt az első hivatalos automatizálós projektem, ami előtt még kaptam HP képzést is, bár ennél a munka és a szükséges tudás összeszedése internetről sokkal hasznosabbnak bizonyult. Ahogy nézem, a HP dolgai igencsak megváltoztak, más kezeli őket.

    HP ALM kapcsán a Gurunál találtam egy értékelhető leírást, és a jól emlékszem, én ennek az oldalnak használtam fel a tudásanyagát annak idején. Viszont jól látszik, hogy elszaladt az idő felette. Talán az egyik cimborám kérdezte pár éve, hogy mi a véleményem egy ilyen projektről, és már akkor azt mondtam, hogy kerülje el, mert nincs jövője.

    Annak idején ez az ökoszisztéma igencsak jól működött, bár ára is volt (cég fizette). Az ALM végezte a központosítást, az UFT pedig az automata tesztek fejlesztésért volt felelős.

    Így nézett ki az UFT.

    Az ALM pedig így.

    Szerintem ez a kettő együtt akkoriban zseniális párost alkotott.

    Katalon Studio

    Kísérletezgettem vele annak idején. Még tetszett is, de valahogy körülményesnek ítéltem meg a használatát. Ennél egy IDEs kódszerkesztővel jobban és minőségibben lehet/lehetett dolgozni. Az pozitív volt, hogy próbálta egy IDE-n belül kezelni a dolgokat, mint a HP UFT, viszont egy idő után kezdett átláthatatlanná válni számomra. Azóta egyébként valószínűleg ez is sokat fejlődött, bár nekem nem volt időm követni a változásokat.

    Valami ilyesmire emlékszem.

    Cypress + JavaScript

    Na ezt imádtam. Könnyedén és gyorsan lehetett benne dolgozni, bár csak 1 évet töltöttem vele. Egy negatívuma azért van/volt, hogy az async/await dolgokat maga kezeli. Ez az esetek túlnyomó többségében nagyon jól működik, de amikor valamiért ez nem jó, az fájdalmas tud lenni.

    Ha jól rémlik, én is VS Code-dal használtam, illetve GitLab-ban futottak a tesztek.

    Ha jól sejtem VS Codeban.

    Playwright + TypeScript

    Abszolút kedvenc. 3 évet töltöttem vele, és imádtam minden percet. Annyira könnyed és légies, és gyorsan lehet vele haladni annak köszönhetően, hogy zseniálisan van felépítve benne szinte minden, hogy csak ajánlani tudom.

    Több különböző nyelvet is támogat, bár nekem a TypeScript volt használatban. Illetve nagyon jól dokumentált. Nem volt szükség sok Google keresésre, mivel a leírás hozzá megválaszolt mindent.

    Ez pedig ilyen volt.

  • Java, Selenium és REST-Assured

    Ennek a bejegyzésnek nem a teljesség a célja, hanem, hogy egy rövid bemutatónk keresztül elkezdhető legyen egy JAVA-s project Seleniummal és/vagy REST-Assured-dal. A kód minősége sem arra készül, hogy ne lehessen belekötni, inkább, mint írtam csak egy könnyen átlátható példa az egész.

    IntelliJ IDEA

    Az IntelliJ IDEA egy kiemelt integrált fejlesztői környezet (IDE), amelyet elsősorban Java és Kotlin szoftverfejlesztéshez használnak. A JetBrains által fejlesztett központi munkaterületként működik, és olyan fejlett funkciókat kínál, mint az intelligens kódkiegészítés, a valós idejű hibaelemzés, az automatizált kódrefaktorálás, valamint a beépített eszközök teszteléshez, profilalkotáshoz és verziókövetéshez.

    Lépések Windows 10-en:

    • IntelliJ IDEA telepítés
    • JAVA futtató és fejlesztő (JDK) telepítés
    • Test Automation plugin
    • pom.xml fájl a függések telepítése miatt
    • első tesztek megírása

    Nézzük és akkor a lépéseket. Első körben töltsük le és telepítsük fel (alapértelmezett ajánlott) az IntelliJ IDEA-t. Majd pedig a számunkra megfeleőnek tűnő JAVA verziókat. Itt sem látom, hogy egy demó keretein belül miért térnék el az alapértelmezett telepítéstől, de el tudom képzelni, hogy más, tervezett rendszer esetén ez szükséges lehet.

    Nálam ez így néz ki:

    java -version
    java version "26.0.1" 2026-04-21
    Java(TM) SE Runtime Environment (build 26.0.1+8-34)
    Java HotSpot(TM) 64-Bit Server VM (build 26.0.1+8-34, mixed mode, sharing)
    
    javac --version
    javac 26.0.1

    Indítsuk el az IntelliJ IDEA-t majd pedig a File -> Settings -> Plugins alatt telepítsük fel a Test Automation-t a Marketplaceről. Erre azért van szükseg, hogy automatizációhoz szükséges projectek közül is könnyedén tudjunk a jövőben választani.

    Új project létrehozása: File -> New -> Project alatt történik.

    A teljesség igénye nélkül, itt van mód kiválasztani, hogy milyen legyen a project – nálam ugye ez Selenium – majd pedig a nyelvet – JAVA – , a build systemet – Maven -, ami a csomagok kezelését végzi, és számomra ez sokkal kézenfekvőbb, illetve a Test frameworkot – TestNG – ami persze hitvita lehetne, így nem mennék bele a választásom okába, végezetül pedig a JDK verziót, amit egyébként innen vezérelve le is tölthetünk, ha korábban nem tettük volna ezt meg.

    Apache Maven

    Az Apache Maven egy hatékony build automatizálási és projektmenedzsment eszköz, amelyet elsősorban Java alkalmazásokhoz használnak. Leegyszerűsíti a fejlesztést azáltal, hogy egy központosított konfigurációs fájl, a pom.xml (Project Object Model) segítségével kezeli a projekt függőségeit, fordítását, tesztelését és csomagolását. Főbb jellemzők Függőségkezelés: A Maven automatikusan letölti a szükséges könyvtárakat és a tőlük függő bővítményeket a központi online tárházakból, így megkíméli Önt a manuális könyvtárkezeléstől. Szabványosított struktúra: Egységes projektmappa-elrendezést biztosít (pl. src/main/java a kódhoz, src/test/java a tesztekhez), ami intuitívvá teszi a különböző projektek közötti navigációt. Építési életciklusok: A Maven előre definiált fázisokat tartalmaz, mint például a fordítás, tesztelés, csomagolás és telepítés, amelyek lehetővé teszik a szoftverek egységes építését egyszerű parancsokkal. Bővíthetőség: Funkcionalitása jelentősen skálázható az ökoszisztémában elérhető különféle építési bővítmények használatával. Hogyan működik Minden Maven projekt egy pom.xml fájlra támaszkodik, amely a könyvtár gyökerében található. Ez a fájl metaadatokat tartalmaz a projektről, annak külső függőségeiről, build utasításairól és bővítménykonfigurációiról. Amikor egy olyan parancsot futtatsz a terminálban, mint például az mvn clean package, a Maven beolvassa a pom.xml fájlt, letölti a hiányzó függőségeket a Maven Central Repository-ból, lefordítja a forráskódot, lefuttatja a teszteket, és az eredményeket terjeszthető formátumba, például JAR vagy WAR fájlba csomagolja. Források A kezdéshez tekintsd meg az Apache Maven dokumentációját a legújabb verziókról, vagy olvasd el a Telepítési útmutatót a gépeden történő beállításhoz.

    TestNG

    A TestNG egy hatékony, Java-alapú automatizált tesztelési keretrendszer (a név a Test Next Generation rövidítése), széles körben használt egység-, integrációs- és végpontok közötti (end-to-end) tesztekhez. A JUnit és NUnit keretrendszerekből merít inspirációt, de olyan fejlett funkciókat is tartalmaz, mint:Párhuzamos végrehajtás: Tesztek futtatása több szálon (akár metódus, osztály vagy lakosztály/suite szinten) a folyamat felgyorsítása folyamatban.Anotációk használata: Egyszerű kódcímkék (pl. @Test, @DataProvider)azonosítás. Adatvezérelt tesztelés a @DataProviosítás tesztelése vagy változók definiálása XML fájlokban.Csoport és függőségek: Tesztek logikai csoportokba rendezése és függőségek meghatározása a tesztelési sorrend biztosítására.Rendkívül népszerű választás keretrendszerek (pl. Selenium) automatizálásához, és könnyen integrálható olyan build eszközökkel, mint a Maven vagy a Gradle.

    POM fájl

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>org.example</groupId>
        <artifactId>selenium-java-testing</artifactId>
        <version>1.0-SNAPSHOT</version>
        <name>selenium-java-testing</name>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <maven.compiler.target>17</maven.compiler.target>
            <maven.compiler.source>17</maven.compiler.source>
            <junit.version>5.11.3</junit.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.seleniumhq.selenium</groupId>
                <artifactId>selenium-java</artifactId>
                <version>4.25.0</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.assertj</groupId>
                <artifactId>assertj-core</artifactId>
                <version>3.26.3</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-api</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.junit.jupiter</groupId>
                <artifactId>junit-jupiter-engine</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <!-- Source: https://mvnrepository.com/artifact/org.testng/testng -->
            <dependency>
                <groupId>org.testng</groupId>
                <artifactId>testng</artifactId>
                <version>7.12.0</version>
                <scope>test</scope>
            </dependency>
            <!-- Source: https://mvnrepository.com/artifact/io.rest-assured/rest-assured -->
            <dependency>
                <groupId>io.rest-assured</groupId>
                <artifactId>rest-assured</artifactId>
                <version>6.0.0</version>
                <scope>test</scope>
            </dependency>
            <!-- Source: https://mvnrepository.com/artifact/io.rest-assured/json-path -->
            <dependency>
                <groupId>io.rest-assured</groupId>
                <artifactId>json-path</artifactId>
                <version>6.0.0</version>
                <scope>compile</scope>
            </dependency>
            <!-- Source: https://mvnrepository.com/artifact/io.rest-assured/json-schema-validator -->
            <dependency>
                <groupId>io.rest-assured</groupId>
                <artifactId>json-schema-validator</artifactId>
                <version>6.0.0</version>
                <scope>compile</scope>
            </dependency>
            <!-- Source: https://mvnrepository.com/artifact/org.hamcrest/hamcrest -->
            <dependency>
                <groupId>org.hamcrest</groupId>
                <artifactId>hamcrest</artifactId>
                <version>3.0</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </project>

    Selenium

    Selenium

    A Selenium WebDriver lehetővé teszi a böngészők közötti kompatibilitás tesztelését, és közvetlenül kommunikálva vezérli a böngészőket. Szinte minden programozási nyelvet támogat, beleértve a Java, Python, C#, Perl, Ruby és PHP nyelveket. A Selenium WebDriver a következő operációs rendszereket támogatja: Windows, Mac OS, Linux és Solaris.

    Az tesztem arra hivatott, hogy egy nagyon alap feladatot lásson el, miszerint elnavigál egy oldalra, név alapján rákattint a kártyára, majd pedig megvizsgálja, hogy a product page címe megfelel annak, ahová navigáltunk. Itt két dolgot akartam kipróbálni.

    Az egyik a DataProvider, ami jelen esetben egy tömb, ami adatvezérlőként működik, és a teszt az ebből kapott adatok alapján hajtódik végre.

    @DataProvider(name = "productData",...

    A másik pedig, hogy ezek a tesztek headless módban, párhúzamosan fussanak úgy, hogy ne akadjanak össze.

    ..., parallel = true)

    Ami ez utóbbinál fontos, hogy szálakra kell bontani a webdrivert, hogy azok a párhúzamos futás során ne üssék egymást, illetve szükséges egy testng.xml fájl néhány beállításhoz.

    private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
    private static final ThreadLocal<MainPage> mainPage = new ThreadLocal<>();

    Párhúzamosítás, ahol .set(), vagy épp .get() metódusok használataval állítsjuk be, vagy épp erjük el a megfelelő szálunkat.

    MainPageTest
    package org.example.seleniumjavatesting;
    
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.chrome.ChromeDriver;
    import org.openqa.selenium.chrome.ChromeOptions;
    import org.testng.Assert;
    import org.testng.annotations.*;
    
    import java.time.Duration;
    
    public class MainPageTest {
        private static final ThreadLocal<WebDriver> driver = new ThreadLocal<>();
        private static final ThreadLocal<MainPage> mainPage = new ThreadLocal<>();
    
        @BeforeMethod
        public void setUp() {
            ChromeOptions options = new ChromeOptions();
            options.addArguments("--headless=new");
            driver.set(new ChromeDriver(options));
            driver.get().manage().window().maximize();
            driver.get().manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
            mainPage.set(new MainPage(driver.get()));
        }
    
        @AfterMethod
        public void tearDown() {
            if (driver.get() !=null) {
                driver.get().quit();
            }
        }
    
        @DataProvider(name = "productData", parallel = true)
        public Object[][] provideData() {
            return new Object[][] {
                    {"Fjallraven - Foldsack No. 1 Backpack, Fits 15 Laptops"},
                    {"Mens Casual Premium Slim Fit T-Shirts"},
                    {"Mens Cotton Jacket"}
            };
        }
    
        @Test(dataProvider = "productData")
        public void openProductPage(String productName) {
            // given
            mainPage.get().navigateToPage("/home");
    
            // when
            ProductPage productPage = mainPage.get().clickOnCard(mainPage.get().getCard(productName));
    
            // then
            Assert.assertEquals(productName, productPage.getProductName(), "Non the expected product page opens!");
        }
    }

    testng.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
    <suite data-provider-thread-count="3" name="MainPageTest">
        <test name="openProductPage">
            <classes>
                <class name="org.example.seleniumjavatesting.MainPageTest"/>
            </classes>
        </test> <!-- Test -->
    </suite> <!-- Suite -->

    Szálak száma: data-provider-thread-count="3"

    REST-Assured

    REST-Assured

    A REST Assured egy hatékony, nyílt forráskódú Java-alapú könyvtár, amellyel könnyedén tesztelhetők és validálhatók a RESTful API-k. Lehetővé teszi az HTTP kérések (GET, POST, PUT, DELETE stb.) küldését, és az eredmények (státuszkód, választest, fejlécek) elegáns, olvasható formában történő ellenőrzését.A REST Assured legfontosabb jellemzőiBolyhos (fluent) DSL szintaxis: Olyan, mintha angol nyelven írnád a tesztelési lépéseket, ami növeli a kód olvashatóságát és karbantarthatóságát.Integráció: Zökkenőmentesen beépíthető olyan Java keretrendszerekbe, mint a Maven, Gradle, JUnit vagy TestNG.Modern verziók: A 6.x verziók már a Java 17+ környezetet és a Spring 7 keretrendszert is támogatják.

    REST-Assured kapcsán pedig csak egy gyors kísérletezgetés implementációja látható, ami egy GET endpoint hívást hivatott tesztelni.

    ApiTesting
    package org.example.restassured;
    
    import io.restassured.RestAssured;
    import io.restassured.response.Response;
    import org.testng.Assert;
    import org.testng.annotations.Test;
    
    import static io.restassured.RestAssured.given;
    import static org.hamcrest.Matchers.equalTo;
    
    public class ApiTesting {
    
        @Test
        public void whenGet_thenOK() {
            Response response = RestAssured.get("https://ignav.com/api/openapi.json");
    
            Assert.assertEquals(response.statusCode(), 200);
            System.out.println("This is response: " + response.body().prettyPrint());
        }
    
        @Test
        public void whenGet_thenOK_logging() {
            given()
                    .baseUri("https://ignav.com/api")
                .when()
                    .get("/openapi.json")
                .then()
                    .statusCode(200)
                    .body("openapi", equalTo("3.1.0"))
                    .log()
                    .body();
        }
    }

    Folytatás várható, addig is itt van pár link, ami hasznos lehet a témában (Baeldung):