Selenium + TestNG'den Geçiş
El ile kurulmuş bir Selenium + TestNG framework'ü çalıştırıyorsanız, bir driver factory, bir bekleme yardımcısı, bir yeniden deneme analizcisi, hata anında ekran görüntüsü yapıştırması ve bir raporlama entegrasyonu yazdınız — ve şimdi hepsini bakımını yapıyorsunuz. TestFly, tüm bunları tek bir bağımlılık olarak sunar.
Bu rehber, yan yana bir **"mevcut kurulumunuz → TestFly karşılığı"**dır. Kısa özet: bugün bakımını yaptığınız tesisatın çoğu sadece silinir.
TestFly hâlâ Selenium'dur. WebDriver, By, WebElement ve mevcut page-object desenlerinizin tümü hâlâ çalışır — araç değiştirmiyorsunuz, boilerplate'i kaldırıyorsunuz.
Kurulum — bağımlılıkları değiştirin
Önce TestFly bağımlılığını ekleyin. Selenium/WebDriverManager kullanan son sınıfı taşıdıktan sonra tekrar eden bağımlılıkları kaldırın:
<dependency>
<groupId>io.github.hakanngul</groupId>
<artifactId>testfly</artifactId>
<version>1.0.7</version>
</dependency>
TestFly Selenium ve TestNG bağımlılıklarını geçişli getirir. Mevcut sürüm override ayarlarını kontrol edin; kullanmaya devam ettiğiniz raporlama entegrasyonlarının bağımlılıklarını koruyun.
Ardından küçük bir testfly.yml oluşturun — aşağıdaki yapılandırma eşlemesine bakın.
1.0.4 ve öncesi Java 17+ gerektirir; 1.0.6 ve sonrası (güncel 1.0.7 dahil) Java 21 gerektirir. Maven/Gradle, IDE ve CI JDK sürümlerini birlikte güncelleyin. Bağımlılık koordinatı io.github.hakanngul:testfly:1.0.7 şeklindedir. Önce bir test sınıfını taşıyın; eski altyapıyı son kullanıcı sınıf taşınmadan silmeyin. Özel Allure/ExtentReports entegrasyonunu kullanmaya devam ediyorsanız bağımlılığını koruyun.
1. Driver kurulumu
Önce — paralel çalıştırmalar için bir driver factory, ThreadLocal uğraşı ve ikili dosyaları indirmek için WebDriverManager:
public class DriverFactory {
private static final ThreadLocal<WebDriver> DRIVER = new ThreadLocal<>();
public static void createDriver() {
WebDriverManager.chromedriver().setup();
ChromeOptions options = new ChromeOptions();
options.addArguments("--start-maximized");
DRIVER.set(new ChromeDriver(options));
DRIVER.get().manage().timeouts()
.implicitlyWait(Duration.ofSeconds(10));
}
public static WebDriver getDriver() { return DRIVER.get(); }
public static void quitDriver() {
DRIVER.get().quit();
DRIVER.remove();
}
}
public class BaseTest {
@BeforeMethod public void setUp() { DriverFactory.createDriver(); }
@AfterMethod public void tearDown() { DriverFactory.quitDriver(); }
}
Sonra — BaseTest'i genişletin. Driver oluşturma, iş parçacığı başına izolasyon ve teardown sizin için halledilir:
import io.testfly.test.BaseTest;
import org.testng.annotations.Test;
public class LoginTest extends BaseTest {
@Test
public void loginTest() {
open(); // execution.baseUrl adresine gider
// ...
}
}
- WebDriverManager yok. Modern Selenium (4.6+) kendi Selenium Manager'ını içerir ve doğru driver ikili dosyasını otomatik olarak indirir. TestFly onu kullanır —
.setup()çağrılarını ve bağımlılığı silin. Detaylar için bkz. WebDriverManager'dan Geçiş. - ThreadLocal yok.
DriverManager, driver'ı her iş parçacığı için izole eder, böylece paralel çalıştırmalar kutu dışı güvenlidir. - Ham driver'a mı ihtiyacınız var? Hâlâ orada:
getDriver().
implicitlyWait(...) öğesini silin. TestFly'ın locator'ları açıkça otomatik bekler; örtük ve açık beklemeleri karıştırmak, flaky ve yavaş testlerin klasik kaynağıdır.
2. Beklemeler
Önce — her sayfaya import edilen WebDriverWait / ExpectedConditions sarmalayan bir WaitUtils yardımcısı:
public class WaitUtils {
public static WebElement waitVisible(WebDriver driver, By locator) {
return new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.visibilityOfElementLocated(locator));
}
public static void waitClickable(WebDriver driver, By locator) {
new WebDriverWait(driver, Duration.ofSeconds(10))
.until(ExpectedConditions.elementToBeClickable(locator));
}
}
// kullanım
WaitUtils.waitVisible(driver, By.id("login")).click();
Sonra — TestFly locator işlemleri otomatik bekler. getWait() yapılandırılmış Selenium WebDriverWait döndürür; özel koşullarda until(ExpectedConditions...) kullanın:
import org.openqa.selenium.By;
import org.openqa.selenium.support.ui.ExpectedConditions;
find("#login").click(); // tıklanabilirlik için otomatik bekler
getWait().until(ExpectedConditions.invisibilityOfElementLocated(By.cssSelector(".spinner")));
getWait().until(ExpectedConditions.textToBePresentInElementLocated(By.cssSelector("h1"), "Welcome back"));
Thread.sleep() yok, sayfa başına WebDriverWait kurulumu yok, driver taşımak yok. WaitEngine rehberine bakın.
3. Yeniden deneme / flaky testler
Önce — bir IRetryAnalyzer artı onu her metoda bağlayan bir listener:
public class RetryAnalyzer implements IRetryAnalyzer {
private int count = 0;
private static final int MAX = 2;
@Override public boolean retry(ITestResult result) {
return count++ < MAX;
}
}
public class RetryListener implements IAnnotationTransformer {
@Override public void transform(ITestAnnotation ann, Class c,
Constructor ctor, Method m) {
ann.setRetryAnalyzer(RetryAnalyzer.class);
}
}
// + listener'ı testng.xml dosyasına kaydedin
Sonra — tek bir yapılandırma satırı tüm suite için yeniden denemeyi açık hale getirir:
retry:
enabled: true
maxAttempts: 2 # ilk çalıştırma dahil toplam deneme sayısı
Gerektiğinde test başına @Retryable ile geçersiz kılın:
@Test
@Retryable(maxAttempts = 3)
public void flakyTest() { /* ... */ }
Kurtarılan ve hâlâ başarısız olan yeniden denemeler rapor içinde ayrıştırılır. Yeniden Deneme rehberine bakın.
4. Hata durumunda ekran görüntüleri
Önce — onTestFailure içinde driver'a uzanan, bir PNG kodlayan ve onu raporunuzun bulabileceği bir yere yazan bir ITestListener:
public class ScreenshotListener implements ITestListener {
@Override public void onTestFailure(ITestResult result) {
WebDriver driver = DriverFactory.getDriver();
File png = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
// .../screenshots dizinine kopyalayın, rapora ekleyin, IOException ile başa çıkın...
}
}
Sonra — hiçbir şey. TestFly her hatada otomatik olarak bir ekran görüntüsü yakalar ve onu HTML raporuna gömer. Listener'ı silin. Ekran Görüntüleri bölümüne bakın.
5. Raporlama
Önce — ExtentReports/Allure bağlayın: bir listener, @AfterSuite içinde bir flush() ve kodunuza dağılmış test başına günlüğe kaydetme çağrıları.
Sonra — target/testfly-report.html adresinde kendi kendine yeten bir HTML raporu (geçme oranı göstergesi, yeniden denemeler, gömülü ekran görüntüleri, flakiness) ve CI için bir JUnit XML dosyası — her ikisi de her çalıştırmadan sonra otomatik olarak üretilir. Daha zengin raporlar istiyorsanız opsiyonel Adım Günlüğü API'siyle adlandırılmış adımlar ekleyin.
Bkz. HTML Raporu ve JUnit XML.
Neler silinir
| Mevcut kurulumunuz | TestFly |
|---|---|
DriverFactory + ThreadLocal<WebDriver> | ✅ Yerleşik — BaseTest'i genişletin |
WebDriverManager.chromedriver().setup() | ✅ Selenium Manager (otomatik) |
| Örtük bekleme yapılandırması | ✅ Otomatik bekleyen locator'lar |
WaitUtils / WebDriverWait yardımcıları | ✅ WaitEngine + otomatik bekleme |
IRetryAnalyzer + IAnnotationTransformer | ✅ retry: yapılandırması + @Retryable |
Hata anında ekran görüntüsü ITestListener | ✅ Hata durumunda otomatik |
| ExtentReports/Allure bağlantısı | ✅ HTML raporu + JUnit XML |
@BeforeMethod / @AfterMethod yaşam döngüsü yapıştırması | ✅ Framework tarafından yönetilen yaşam döngüsü |
Page object'leriniz ve @Test metotlarınız aynı kalır — sadece kısalırlar.
Yalnızca TestFly ile aynı işi yapan eski lifecycle/retry/screenshot listener kayıtlarını kaldırın. İş kurallarını, test verisini veya harici entegrasyonları yöneten listener'ları koruyun. TestFly listener'larını ikinci kez kaydetmeyin.
Yapılandırma eşlemesi
testng.xml özniteliklerinde ve dağınık sabitlerde yaşayan ayarlar tek bir dosyaya taşınır:
execution:
mode: local
baseUrl: https://your-app.com
parallel: methods # şuydu: <suite parallel="methods">
threadCount: 4 # şuydu: thread-count="4"
browser:
name: chrome
headless: false # CI algılandığında otomatik olarak true zorlanır
timeouts:
explicit: 10 # şuydu: WaitUtils sabitiniz
pageLoad: 30
retry:
enabled: true
maxAttempts: 2 # şuydu: RetryAnalyzer MAX
Test sınıflarınızı listelemek için hâlâ minimal bir testng.xml tutarsınız — TestFly kendi listener'larını kaydeder, bu nedenle <listeners> bloğundan yalnızca tekrar eden kayıtları kaldırın. Her seçenek için Yapılandırma Referansına bakın.
Kademeli geçiş
Her şeyi bir kerede dönüştürmek zorunda değilsiniz:
- Bağımlılığı ve bir
testfly.ymldosyası ekleyin. - Bir test sınıfını
BaseTest'e yönlendirin,@BeforeMethod/@AfterMethodiçinden driver oluşturma/kapatma kodunu çıkarın; iş verisi hazırlığı ve temizliğini koruyun ve çalıştırın. - Yeşil olduğunda, son sınıf onlara atıfta bulunmayı bıraktıkça
DriverFactory,WaitUtils, yeniden deneme analizciniz ve ekran görüntüsü listener'ınızı silin.
Geçirilmiş sınıfları önce ayrı bir TestNG koşusunda doğrulayın. Eski listener ve driver teardown kodunun TestFly tarafından yönetilen testlere uygulanmasını önleyin; karma suite davranışını paralelliği açmadan kontrol edin.
Mevcut Page Object'leri koruyun
Driver alan mevcut bir Page Object'i new LoginPage(getDriver()) ile kullanabilirsiniz. İlk geçişte By, WebElement, PageFactory ve TestNG assertion'larını yeniden yazmanız gerekmez. Otomatik bekleme TestFly Locator işlemlerindedir; ham WebElement çağrıları kendi Selenium beklemelerine ihtiyaç duyar.
TestFly fluent API'sine geçerken locator'ları sayfa nesnesinde tanımlayın:
import io.testfly.test.BasePage;
import io.testfly.locator.Locator;
public class LoginPage extends BasePage {
private final Locator username = find("#username");
private final Locator password = find("#password");
private final Locator submit = find("button[type='submit']");
public void login(String user, String pass) {
username.type(user);
password.type(pass);
submit.click();
}
}
Sonraki adımlar
- Başlarken — 5 dakikalık sürüm
- BaseTest / BasePage — genişleteceğiniz temel sınıflar
- Erişilebilirlik Öncelikli Locator'lar — boilerplate gittikten sonra
getByRole/getByLabel - Yapılandırma Referansı — tam
testfly.yml