Takip et

Selenium ile Temiz Page Object Model (POM) Kurulumu

Web otomasyon testlerinizde karmaşıklıkla mı boğuşuyorsunuz? Kodunuz okunmaz hale mi geldi?

Selenium ile Temiz Page Object Model (POM) Kurulumu

Web otomasyon testlerinizde karmaşıklıkla mı boğuşuyorsunuz? Kodunuz okunmaz hale mi geldi? Selenium ile yazdığınız testlerin sürdürülebilirliği ve yeniden kullanılabilirliği konusunda endişeleriniz mi var? Bu makale, Selenium ile Java kullanarak temiz ve etkili bir Page Object Model (POM) kurmanın tüm detaylarını adım adım açıklayarak bu sorunlara çözüm sunmayı amaçlıyor. Okuyucular, POM’un temel prensiplerinden başlayarak, gerçek dünya senaryolarına uygun, sürdürülebilir ve ölçeklenebilir otomasyon testleri yazma becerisi kazanacaklar.

Neden Page Object Model (POM) Kullanmalısınız?

Web otomasyon testleri geliştirirken, özellikle büyük ve karmaşık uygulamalar söz konusu olduğunda, kodun yönetimi ve bakımı önemli bir zorluk haline gelebilir. Test senaryoları arttıkça, aynı elementleri veya işlemleri tekrar tekrar kodlamak, kod tekrarına (code duplication) yol açar. Bu durum, bir elementin XPath’i veya CSS seçicisi değiştiğinde, bu elementi kullanan tüm testleri güncellemek zorunda kalacağınız anlamına gelir. Bu da hem zaman kaybına hem de hata yapma olasılığının artmasına neden olur. İşte tam bu noktada Page Object Model (POM) devreye girer. POM, nesne yönelimli programlama (Object-Oriented Programming – OOP) prensiplerinden yararlanarak, web uygulamasının her bir sayfasını veya önemli bir bölümünü bir Java sınıfı olarak temsil eden bir tasarım desenidir. Bu sınıflar, o sayfadaki elementleri (butonlar, metin kutuları, linkler vb.) ve bu elementlerle etkileşim kurmak için kullanılan metotları (tıklama, metin girme, bilgi alma vb.) içerir. Yani, bir sayfanın “davranışını” kapsüller. Bu yaklaşımın temel avantajları şunlardır:

  • Sürdürülebilirlik: Bir web sayfasındaki bir elementin konumu (selector) değiştiğinde, bu değişikliği sadece ilgili Page Object sınıfında yapmanız yeterli olur. Bu değişiklik, o Page Object’i kullanan tüm testlere otomatik olarak yansır. Bu, bakım maliyetini önemli ölçüde azaltır.
  • Yeniden Kullanılabilirlik: Sayfa elementleri ve işlemler, merkezi bir yerde tanımlandığı için farklı test senaryolarında kolayca yeniden kullanılabilir. Bu, kod tekrarını önler ve test geliştirme sürecini hızlandırır.
  • Okunabilirlik ve Anlaşılırlık: Test kodları, sayfa elementlerinin soyutlanması sayesinde daha temiz ve okunabilir hale gelir. Test senaryoları, sayfa detaylarından ziyade iş mantığına odaklanır. Örneğin, loginPage.enterUsername("kullaniciadi"); gibi bir satır, driver.findElement(By.id("username")).sendKeys("kullaniciadi"); gibi bir satırdan çok daha anlamlıdır.
  • Test Kapsamının Artması: Kodun daha modüler ve yönetilebilir olması, daha fazla test senaryosu yazmayı ve test kapsamını genişletmeyi kolaylaştırır.
  • Takım Çalışması: Farklı geliştiriciler, uygulamanın farklı sayfalarının Page Object sınıflarını geliştirebilir, bu da takım çalışmasını kolaylaştırır ve projelerin daha hızlı ilerlemesini sağlar.

Özetle, POM, Selenium ile yapılan otomasyon testlerinin kalitesini, verimliliğini ve uzun vadeli bakımını iyileştiren güçlü bir tasarım desenidir. Karmaşık projelerde kodunuzu organize etmenin ve testlerinizi daha profesyonel bir seviyeye taşımanın anahtarıdır.

POM’un Temel Kavramları Nelerdir?

Page Object Model’i etkin bir şekilde kullanabilmek için bazı temel kavramları anlamak önemlidir. Bu kavramlar, POM’un yapısını ve nasıl çalıştığını anlamamıza yardımcı olacaktır. Temel olarak POM, web uygulamasındaki her bir önemli sayfa veya bileşen için ayrı bir Java sınıfı oluşturmaya dayanır. Bu sınıflar, “Page Objects” olarak adlandırılır. Her Page Object sınıfı, temsil ettiği web sayfasındaki belirli elementleri ve bu elementlerle etkileşim kurmak için gereken yöntemleri (methods) içerir.

  • Page Object Sınıfları: Her bir web sayfası veya modül için bir Java sınıfı oluşturulur. Örneğin, bir giriş sayfası için LoginPage, ana sayfa için HomePage, ürün arama sayfası için SearchPage gibi sınıflar oluşturulabilir. Bu sınıfların amacı, temsil ettikleri sayfanın yapısını ve işlevselliğini soyutlamaktır.
  • Element Tanımlamaları: Her Page Object sınıfı içinde, temsil ettiği sayfada bulunan web elementleri (butonlar, metin alanları, linkler vb.) tanımlanır. Bu tanımlamalar genellikle WebElement nesneleri olarak yapılır ve elementlerin bulunması için kullanılan seçiciler (selectors) ile birlikte belirtilir. Seçiciler genellikle XPath, CSS Selector, ID, Name gibi stratejilerle belirlenir. Örneğin, bir giriş sayfasındaki kullanıcı adı metin kutusu şu şekilde tanımlanabilir: @FindBy(id = "username") WebElement usernameField;. Burada @FindBy, PageFactory gibi bir kütüphane kullanıldığında elementin nasıl bulunacağını belirtir.
  • Metotlar (Methods): Page Object sınıfları sadece elementleri tanımlamakla kalmaz, aynı zamanda bu elementlerle etkileşim kuracak yöntemleri de içerir. Bu yöntemler, sayfanın belirli işlevlerini temsil eder. Örneğin, bir LoginPage sınıfında login(String username, String password) adında bir metot olabilir. Bu metot, kullanıcı adı ve şifre alanlarına metin girmeyi ve giriş butonuna tıklamayı içerir. Bu soyutlama sayesinde, test kodları daha okunabilir hale gelir ve sayfa değişiklikleri sadece ilgili Page Object sınıfında güncellenir.
  • Driver Nesnesi: Her Page Object sınıfı, web tarayıcısını kontrol etmek için bir WebDriver nesnesine sahip olmalıdır. Bu nesne, sayfa elementlerini bulmak ve onlarla etkileşim kurmak için kullanılır. Genellikle Page Object sınıflarının constructor’ı (yapıcı metodu) aracılığıyla WebDriver nesnesi bu sınıflara aktarılır.
  • PageFactory (İsteğe Bağlı ama Önerilir): Selenium’un PageFactory, Page Object tasarım desenini uygulamayı kolaylaştıran bir yardımcı sınıftır. Elementleri @FindBy anotasyonları ile tanımlamanıza olanak tanır ve PageFactory.initElements(driver, this); metodu ile tüm elementlerin otomatik olarak başlatılmasını sağlar. Bu, driver.findElement(...) çağrılarını azaltır ve kodun daha temiz olmasını sağlar.

Bu temel kavramları anladığınızda, POM’un nasıl çalıştığına dair sağlam bir temel oluşturmuş olursunuz. Şimdi bu kavramları pratik uygulamaya dökmeye hazırız.

İlk POM Yapınızı Kurma: Adım Adım Kılavuz

Hazırsanız, basit bir web sitesi (örneğin, bir giriş sayfası) üzerinde temiz bir Page Object Model yapısı kurmaya başlayalım. Bu adım adım rehber, size POM’u nasıl uygulayacağınızı gösterecektir. Öncelikle, projenizde aşağıdaki klasör yapısını oluşturmanızı öneririm:


src/
├── main/java/
│   └── com/example/pages/
│       ├── BasePage.java
│       ├── LoginPage.java
│       └── HomePage.java
└── test/java/
    └── com/example/tests/
        └── LoginTest.java

Bu yapı, sayfa sınıflarını ve test sınıflarını ayrı tutarak projenizi düzenli tutmanıza yardımcı olur.

Adım 1: Temel Sayfa Sınıfı (BasePage)

Tüm Page Object sınıflarının ortak özelliklerini barındıracak bir BasePage sınıfı oluşturmak iyi bir pratiktir. Bu sınıf, tüm sayfa sınıfları tarafından miras alınacak (extended) ve WebDriver örneği gibi temel bileşenleri içerecektir. Bu, kod tekrarını önler ve tüm sayfa nesnelerinin tutarlı bir şekilde başlatılmasını sağlar.


package com.example.pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.PageFactory;

public class BasePage {
    protected WebDriver driver;

    public BasePage(WebDriver driver) {
        this.driver = driver;
        // PageFactory'yi kullanarak tüm @FindBy anotasyonlu elementleri başlatır.
        PageFactory.initElements(driver, this);
    }

    // Genel amaçlı metotlar eklenebilir, örneğin sayfa başlığını alma gibi.
    public String getPageTitle() {
        return driver.getTitle();
    }
}

Bu BasePage sınıfı, her Page Object sınıfının ihtiyacı olan WebDriver örneğini alır ve PageFactory.initElements ile elementlerin otomatik olarak başlatılmasını sağlar. Ayrıca, tüm sayfalarda ortak olarak kullanılabilecek getPageTitle() gibi metotlar da burada tanımlanabilir.

Adım 2: Giriş Sayfası (LoginPage)

Şimdi, örneğimizdeki giriş sayfasını temsil edecek LoginPage sınıfını oluşturalım. Bu sınıf, BasePage‘den miras alacak ve giriş sayfasındaki elementleri ile giriş işlemini gerçekleştiren metotları içerecektir.


package com.example.pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class LoginPage extends BasePage {

    // Giriş sayfasındaki elementleri tanımlıyoruz.
    @FindBy(id = "username")
    private WebElement usernameField;

    @FindBy(id = "password")
    private WebElement passwordField;

    @FindBy(xpath = "//button[@type='submit']")
    private WebElement loginButton;

    @FindBy(className = "error-message") // Örneğin bir hata mesajı elementi
    private WebElement errorMessage;

    // Constructor, BasePage'in constructor'ını çağırır.
    public LoginPage(WebDriver driver) {
        super(driver);
    }

    // Kullanıcı adı alanına metin giren metot.
    public void enterUsername(String username) {
        usernameField.sendKeys(username);
    }

    // Şifre alanına metin giren metot.
    public void enterPassword(String password) {
        passwordField.sendKeys(password);
    }

    // Giriş butonuna tıklayan metot.
    public void clickLoginButton() {
        loginButton.click();
    }

    // Giriş işlemini gerçekleştiren metot.
    public HomePage login(String username, String password) {
        enterUsername(username);
        enterPassword(password);
        clickLoginButton();
        // Giriş başarılı olduğunda ana sayfaya yönlendirme beklenir.
        // Bu noktada yeni bir HomePage nesnesi döndürülür.
        return new HomePage(driver);
    }

    // Hata mesajını getiren metot.
    public String getErrorMessage() {
        return errorMessage.getText();
    }
}

Bu sınıfta, @FindBy anotasyonları ile elementler tanımlanmış ve bu elementlerle etkileşim kurmak için enterUsername, enterPassword, clickLoginButton gibi metotlar oluşturulmuştur. En önemlisi, login metodu, tüm giriş adımlarını tek bir çağrıda gerçekleştiren bir soyutlama sunar ve başarılı bir giriş sonrası HomePage nesnesini döndürür.

Adım 3: Ana Sayfa (HomePage)

Giriş yaptıktan sonra karşımıza çıkacak olan ana sayfayı temsil eden HomePage sınıfını oluşturalım. Bu sınıf da BasePage‘den miras alacak ve ana sayfadaki ilgili elementleri ve işlemleri içerecektir.


package com.example.pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;

public class HomePage extends BasePage {

    @FindBy(xpath = "//h1[contains(text(),'Hoş Geldiniz')]")
    private WebElement welcomeMessage;

    @FindBy(linkText = "Çıkış Yap")
    private WebElement logoutLink;

    public HomePage(WebDriver driver) {
        super(driver);
    }

    public String getWelcomeMessage() {
        return welcomeMessage.getText();
    }

    public void clickLogout() {
        logoutLink.click();
    }

    // Ana sayfaya özel başka metotlar buraya eklenebilir.
}

HomePage sınıfı, ana sayfadaki karşılama mesajını ve çıkış yap linkini temsil eder. Bu, testlerimizin ana sayfaya ulaşıp ulaşmadığımızı doğrulamasını veya çıkış işlemini gerçekleştirmesini sağlar.

Adım 4: Test Sınıfı (LoginTest)

Şimdi, oluşturduğumuz Page Object’leri kullanarak bir test senaryosu yazalım. LoginTest sınıfı, Selenium WebDriver’ı başlatacak, LoginPage nesnesini oluşturacak ve giriş işlemini gerçekleştirecektir. Bu test sınıfı, Page Object’lerin nasıl kullanılacağını gösteren bir örnektir.


package com.example.tests;

import com.example.pages.HomePage;
import com.example.pages.LoginPage;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

import java.util.concurrent.TimeUnit;

public class LoginTest {

    private WebDriver driver;
    private LoginPage loginPage;
    private HomePage homePage;

    @BeforeMethod
    public void setUp() {
        // WebDriver'ı başlat
        System.setProperty("webdriver.chrome.driver", "path/to/your/chromedriver"); // ChromeDriver yolunu güncelleyin
        driver = new ChromeDriver();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Genel bekleme süresi
        driver.get("http://your-web-app-url.com/login"); // Uygulamanızın giriş URL'sini güncelleyin

        // Page Object'leri başlat
        loginPage = new LoginPage(driver);
    }

    @Test
    public void validLoginTest() {
        // LoginPage'deki login metodunu kullanarak giriş yap
        homePage = loginPage.login("testuser", "password123"); // Geçerli kullanıcı adı ve şifre

        // Girişin başarılı olduğunu doğrula (Ana sayfada karşılama mesajı gibi)
        Assert.assertTrue(homePage.getWelcomeMessage().contains("Hoş Geldiniz"), "Giriş başarılı olmalıydı.");
        Assert.assertEquals(homePage.getPageTitle(), "Ana Sayfa", "Ana sayfa başlığı yanlış.");
    }

    @Test
    public void invalidLoginTest() {
        // Geçersiz kullanıcı adı ve şifre ile giriş yapmayı dene
        loginPage.enterUsername("invaliduser");
        loginPage.enterPassword("wrongpassword");
        loginPage.clickLoginButton();

        // Hata mesajının göründüğünü doğrula
        Assert.assertTrue(loginPage.getErrorMessage().contains("Geçersiz kullanıcı adı veya şifre"), "Hata mesajı görünmeliydi.");
    }

    @AfterMethod
    public void tearDown() {
        // WebDriver'ı kapat
        if (driver != null) {
            driver.quit();
        }
    }
}

Bu test sınıfında, @BeforeMethod ile her testten önce WebDriver başlatılır ve giriş URL’sine gidilir. Ardından LoginPage nesnesi oluşturulur. validLoginTest metodu, loginPage.login() metodunu kullanarak giriş yapar ve HomePage nesnesini alır. Sonrasında, HomePage‘den alınan karşılama mesajı ile girişin başarılı olup olmadığı doğrulanır. invalidLoginTest metodu ise geçersiz bilgilerle giriş yapmayı dener ve beklenen hata mesajının göründüğünü kontrol eder. Son olarak, @AfterMethod ile her testten sonra WebDriver kapatılır.

Gerçek Dünya Senaryoları ve Vaka Analizleri

Yukarıdaki temel kurulum, POM’un nasıl çalıştığını göstermektedir. Ancak gerçek dünya uygulamaları genellikle daha karmaşıktır ve farklı senaryolarla karşılaşırız. Bu bölümde, daha gelişmiş POM uygulamalarını ve sık karşılaşılan durumları ele alacağız.

Karmaşık Sayfaları Yönetme

Bazı web sayfaları oldukça karmaşık olabilir, birçok bölümü ve iç içe geçmiş elementleri barındırabilir. Bu tür durumlarda, tek bir büyük Page Object sınıfı yerine, sayfayı daha küçük, yönetilebilir parçalara ayırmak faydalı olacaktır. Örneğin, bir e-ticaret sitesinin ürün detay sayfasında, ürün bilgileri, resim galerisi, yorumlar bölümü ve “sepete ekle” butonu gibi farklı bölümler olabilir. Bu bölümler için ayrı “komponent” sınıfları oluşturabiliriz.

Vaka Analizi: E-ticaret Sitesi Ürün Detay Sayfası

Diyelim ki bir ürün detay sayfasını test ediyoruz. Bu sayfada şunlar bulunuyor:

  • Ürün Adı, Fiyatı, Açıklaması
  • Ürün Resimleri (bir galeri içinde)
  • Miktar Seçici
  • “Sepete Ekle” Butonu
  • Ürün Yorumları Bölümü

Bu sayfayı yönetmek için şu yapıyı düşünebiliriz:


// Ana sayfa nesnesi
public class ProductDetailsPage extends BasePage {
    // ...
    // Ürün bilgileri bölümü için ayrı bir sınıf
    @FindBy(css = ".product-info-section")
    private WebElement productInfoSectionElement;
    private ProductInfoComponent productInfoComponent;

    // Resim galerisi için ayrı bir sınıf
    @FindBy(css = ".image-gallery")
    private WebElement imageGalleryElement;
    private ImageGalleryComponent imageGalleryComponent;

    // Sepete ekle butonu
    @FindBy(id = "add-to-cart-button")
    private WebElement addToCartButton;

    public ProductDetailsPage(WebDriver driver) {
        super(driver);
        // Komponentleri de başlat
        productInfoComponent = new ProductInfoComponent(productInfoSectionElement);
        imageGalleryComponent = new ImageGalleryComponent(imageGalleryElement);
    }

    public void clickAddToCart() {
        addToCartButton.click();
    }

    // Komponent metotlarını kullan
    public String getProductName() {
        return productInfoComponent.getProductName();
    }

    public void selectQuantity(int quantity) {
        // Miktar seçici ile ilgili işlemler
    }
    // ... diğer metotlar
}

// Ürün bilgileri bölümü için komponent sınıfı
public class ProductInfoComponent {
    private WebElement element;

    @FindBy(css = "h1.product-title")
    private WebElement productName;
    @FindBy(css = ".product-price")
    private WebElement productPrice;

    public ProductInfoComponent(WebElement element) {
        this.element = element;
        // Komponentin kendi elementleri için de PageFactory kullanılabilir
        PageFactory.initElements(new org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory(element), this);
    }

    public String getProductName() {
        return productName.getText();
    }

    public String getProductPrice() {
        return productPrice.getText();
    }
}

// Resim galerisi için komponent sınıfı
public class ImageGalleryComponent {
    private WebElement element;

    @FindBy(css = ".main-image")
    private WebElement mainImage;
    @FindBy(css = ".thumbnail")
    private List thumbnails;

    public ImageGalleryComponent(WebElement element) {
        this.element = element;
        PageFactory.initElements(new org.openqa.selenium.support.pagefactory.AjaxElementLocatorFactory(element), this);
    }

    public void clickThumbnail(int index) {
        if (index >= 0 && index < thumbnails.size()) {
            thumbnails.get(index).click();
        }
    }

    public String getMainImageSrc() {
        return mainImage.getAttribute("src");
    }
}

Bu yaklaşımda, ProductDetailsPage ana sayfa nesnesi olarak kalırken, ProductInfoComponent ve ImageGalleryComponent gibi sınıflar, sayfanın belirli bölümlerini yönetir. Bu, kodun daha modüler, anlaşılır ve bakımı daha kolay olmasını sağlar. Her komponent, kendi içindeki elementleri ve etkileşimleri yönetir.

Dinamik Elementler ve Beklemeler

Web uygulamaları genellikle dinamik içeriklere sahiptir. Elementler sayfa yüklendiğinde hemen görünmeyebilir, JavaScript ile sonradan yüklenebilir veya belirli bir süre sonra kaybolabilir. Bu durumlar için Selenium'da beklemeler (waits) kullanmak kritiktir. POM'da bu beklemeleri Page Object sınıflarının içine entegre etmek, testlerin daha kararlı olmasını sağlar.

  • Implicit Wait (Örtülü Bekleme): driver.manage().timeouts().implicitlyWait(seconds, TimeUnit.SECONDS); ile tanımlanır. Belirtilen süre boyunca WebDriver, bir elementi bulamazsa bekler. Bu, tüm elementler için geçerlidir ve genellikle @BeforeMethod veya test başlangıcında bir kere ayarlanır.
  • Explicit Wait (Açık Bekleme): Belirli bir koşul sağlanana kadar beklemeyi sağlar. Bu, daha kontrollü ve güvenilirdir. WebDriverWait ve ExpectedConditions sınıfları ile kullanılır.

POM içinde Explicit Wait kullanımı:


package com.example.pages;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.FindBy;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.time.Duration;

public class LoginPage extends BasePage {

    @FindBy(id = "username")
    private WebElement usernameField;

    @FindBy(id = "password")
    private WebElement passwordField;

    @FindBy(xpath = "//button[@type='submit']")
    private WebElement loginButton;

    public LoginPage(WebDriver driver) {
        super(driver);
    }

    public void enterUsername(String username) {
        // Kullanıcı adı alanı görünene kadar bekle
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10)); // 10 saniye bekle
        WebElement element = wait.until(ExpectedConditions.visibilityOf(usernameField));
        element.sendKeys(username);
    }

    public void clickLoginButton() {
        // Giriş butonu tıklanabilir olana kadar bekle
        WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
        WebElement element = wait.until(ExpectedConditions.elementToBeClickable(loginButton));
        element.click();
    }

    // ... diğer metotlar
}

Bu örnekte, enterUsername ve clickLoginButton metotları, ilgili elementler görünene veya tıklanabilir hale gelene kadar beklemek için WebDriverWait kullanır. Bu, testlerin kararlılığını önemli ölçüde artırır, özellikle ağ yavaşlığı veya sunucu yanıt sürelerindeki dalgalanmalar durumunda.

Veri Sürüklü Testler (Data-Driven Testing) için POM

Veri sürüklü testler (Data-Driven Testing), aynı test senaryosunu farklı veri setleriyle çalıştırmayı içerir. POM, bu tür testleri desteklemek için idealdir. Test sınıfları, veriyi bir dış kaynaktan (CSV, Excel, veritabanı vb.) okuyabilir ve bu veriyi Page Object metotlarına argüman olarak geçirebilir.

Örneğin, bir giriş testini farklı kullanıcı adları ve şifrelerle çalıştırmak isteyebilirsiniz. Test sınıfınızda veriyi okuyup, her bir veri seti için loginPage.login() metodunu çağırabilirsiniz.


@Test(dataProvider = "loginData")
public void multipleLoginsTest(String username, String password, boolean expectedSuccess) {
    HomePage homePage = loginPage.login(username, password);

    if (expectedSuccess) {
        Assert.assertTrue(homePage.getWelcomeMessage().contains("Hoş Geldiniz"), "Giriş başarılı olmalıydı.");
    } else {
        // Hata durumunu kontrol et
        Assert.assertTrue(loginPage.getErrorMessage().contains("Geçersiz"), "Hata mesajı bekleniyordu.");
    }
}

@DataProvider(name = "loginData")
public Object[][] getLoginData() {
    // Buraya CSV, Excel veya hardcoded veriler eklenebilir
    return new Object[][] {
        {"validuser1", "pass1", true},
        {"invaliduser", "wrongpass", false},
        {"validuser2", "pass2", true}
    };
}

Bu örnekte, TestNG'nin @DataProvider özelliği kullanılarak giriş verileri sağlanır. Her bir veri seti için multipleLoginsTest metodu çalışır ve loginPage.login() metodu bu verilerle çağrılır. Bu, testlerinizi daha esnek ve kapsamlı hale getirir.

İleri Düzey İpuçları ve Püf Noktaları

POM'u daha etkili kullanmanıza yardımcı olacak bazı ileri düzey ipuçları ve yaygın olarak karşılaşılan sorunlara çözümler:

  • Sabitleri (Constants) Kullanma: URL'ler, kullanıcı adları, şifreler gibi tekrar eden değerleri doğrudan kod içine yazmak yerine, sabitler (constants) olarak tanımlayın. Bunları BasePage'de veya ayrı bir Constants sınıfında saklayabilirsiniz. Bu, değerleri tek bir yerden güncellemenizi kolaylaştırır.
  • Enum'lar ile Durum Yönetimi: Bazı durumlarda, bir sayfanın farklı durumları olabilir (örneğin, bir ürün sepette var veya yok). Bu durumları yönetmek için Enum'lar (enumerations) kullanmak kodu daha okunabilir hale getirebilir.
  • Hata Yönetimi ve Raporlama: POM sınıflarına, olası hataları yakalayan ve raporlama araçlarına (örneğin, ExtentReports, Allure Reports) bilgi gönderen metotlar ekleyebilirsiniz. Örneğin, bir element bulunamadığında veya bir işlem başarısız olduğunda ekran görüntüsü alıp raporlayabilirsiniz.
  • Test Verisi Yönetimi: Büyük projelerde test verilerini yönetmek önemlidir. Veri tabanları, harici dosyalar (Excel, JSON, YAML) veya test veri yönetim araçları kullanarak verilerinizi merkezi bir yerde saklayın ve POM sınıflarınıza erişilebilir hale getirin.
  • Modülerlik ve Tek Sorumluluk Prensibi (SRP): Her Page Object sınıfının yalnızca bir sorumluluğu olmalıdır: temsil ettiği sayfanın veya bileşenin elementlerini ve davranışlarını yönetmek. Bir sınıf çok fazla iş yapmaya başladığında, onu daha küçük, daha odaklı sınıflara bölmeyi düşünün.
  • Soyutlama Seviyesi: POM'un amacı soyutlamadır. Test kodunuzun, hangi elementlerin nasıl bulunduğuna dair detayları bilmemesi gerekir. Testler, sayfanın ne yaptığını anlamalı, nasıl yaptığını değil. Örneğin, loginPage.login("user", "pass") demek, testin amacını net bir şekilde ifade eder.
  • Sayfa Yüklenmesini Bekleme: Her Page Object'in constructor'ında veya ilgili metotlarında, sayfanın tamamen yüklenmesini sağlamak için uygun beklemeleri (Explicit Waits) kullanın. Bu, testlerin kararlılığını artırır.
  • Page Factory Alternatifleri: Page Factory harika bir araç olsa da, bazı durumlarda (örneğin, dinamik elementler veya karmaşık DOM yapıları) manuel element bulma (driver.findElement()) daha esnek olabilir. Ancak, PageFactory.initElements() kullanmak, kodunuzu daha temiz tutmanın en iyi yollarından biridir.
  • Framework Entegrasyonu: POM'u JUnit, TestNG gibi test framework'leri ve Maven, Gradle gibi build araçlarıyla entegre etmek, projenizin daha profesyonel ve yönetilebilir olmasını sağlar.

Bu ipuçları, POM'u sadece bir tasarım deseni olmaktan çıkarıp, gerçek dünya otomasyon projelerinizde güçlü bir araç haline getirmenize yardımcı olacaktır.

Sonuç ve Sıkça Sorulan Sorular

Selenium ile temiz bir Page Object Model (POM) kurmak, otomasyon testlerinizin sürdürülebilirliğini, okunabilirliğini ve yeniden kullanılabilirliğini önemli ölçüde artırır. Bu makalede, POM'un temel prensiplerini, adım adım kurulumunu, karmaşık senaryoları yönetme yöntemlerini ve ileri düzey ipuçlarını ele aldık. Temel BasePage sınıfından başlayarak, özel sayfa sınıfları (LoginPage, HomePage) oluşturmayı ve bu sınıfları test senaryolarında nasıl kullanacağımızı gördük. Ayrıca, dinamik elementleri yönetmek ve veri sürüklü testler için POM'u nasıl uyarlayacağımızı da inceledik.

POM'u benimsemek, başlangıçta biraz daha fazla çaba gerektirse de, uzun vadede test otomasyon projelerinizin başarısı için kritik öneme sahiptir. Kodunuz daha düzenli, daha az hataya açık ve gelecekteki değişikliklere daha kolay adapte olabilir hale gelecektir. Bu da geliştirme süreçlerinizi hızlandıracak ve otomasyon testlerinizden alacağınız verimi artıracaktır.

Sıkça Sorulan Sorular (SSS)

  • S: POM'u kullanmak için hangi Java bilmem gerekiyor?
    C: Temel Java bilgisi yeterlidir. Nesne yönelimli programlama (sınıflar, nesneler, miras alma), metodlar ve değişkenler gibi kavramlara hakim olmanız POM'u anlamanız ve uygulamanız için yeterli olacaktır.
  • S: Bir web sayfasında çok fazla element varsa ne yapmalıyım?
    C: Bu durumda sayfayı daha küçük, mantıksal bileşenlere ayırarak ayrı komponent sınıfları oluşturabilirsiniz. Bu, ana Page Object sınıfını daha yönetilebilir tutar.
  • S: POM ile testlerimin hızı artar mı?
    C: POM doğrudan test hızını artırmaz, ancak kodun daha temiz ve bakımı kolay olması sayesinde test geliştirme ve hata ayıklama süreçlerini hızlandırır. Ayrıca, doğru beklemelerin (Explicit Waits) kullanılması, testlerin kararlılığını artırarak gereksiz bekleme sürelerini azaltır.
  • S: POM'u başka otomasyon araçlarıyla da kullanabilir miyim?
    C: Evet, POM, web otomasyonunda yaygın olarak kullanılan bir tasarım desenidir ve Selenium dışındaki araçlarla (örneğin, Playwright, Cypress) da uygulanabilir. Temel prensipler aynıdır.
  • S: Her sayfa için ayrı bir sınıf mı oluşturmalıyım?
    C: Genellikle evet, uygulamanızdaki her ana sayfa veya önemli bir modül için ayrı bir Page Object sınıfı oluşturmak iyi bir pratiktir. Ancak, çok küçük veya sadece birkaç element içeren sayfalar için bu gerekli olmayabilir.

#Selenium #PageObjectModel #Java #WebOtomasyon #TestOtomasyonu #YazilimTesti

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Exit mobile version