Spring Boot ile Selenium WebDriver Test Otomasyonu
Giriş
Test otomasyon projeleri, yazılım geliştirme süreçlerinde güvenilir ve sürdürülebilir bir ürün kalitesi sağlamak amacıyla kullanılan önemli araçlardan biridir. Bu noktada, Spring Boot’un test otomasyon projeleri ile olan ilişkisi, geliştiricilere ve test uzmanlarına bir dizi avantaj sunar. Spring Boot’un temel kavramları, Inversion of Control (IoC) ve Dependency Injection (DI), test otomasyon projelerinde kodun daha okunabilir ve bakımı daha kolay hale gelmesine olanak tanır. Aynı zamanda, Spring Boot’un sunduğu modüler yapı, testlerin parçalara ayrılmasını ve her bir bileşenin ayrı ayrı test edilmesini kolaylaştırır. Bu sayede, bir hata durumunda sorunlu bileşenin tespiti ve düzeltilmesi daha hızlı gerçekleşir.
Test otomasyon projelerinde Spring Boot’un tercih edilmesindeki bir diğer etken, hızlı geliştirme imkanıdır. Spring Initializr kullanılarak projenin başlatılması, temel yapıların otomatik olarak oluşturulmasını sağlar ve bu da geliştiricilere zaman kazandırır. Ayrıca, Spring Boot’un sunduğu otomatik konfigürasyon özellikleri, test otomasyon projelerinde kullanılan bileşenler arasındaki entegrasyonun daha sorunsuz bir şekilde gerçekleştirilmesine yardımcı olur. Spring Boot’un test otomasyon projeleri üzerindeki etkisi, yazılım kalitesini artırmak ve geliştirme süreçlerini optimize etmek isteyen ekipler için önemli bir avantaj sağlar.
Inversion of Control (IoC)
Inversion of Control (IoC), yazılım geliştirme sürecinde başvurulan bir tasarım prensibidir. Geleneksel yazılım geliştirme yaklaşımlarından farklı olarak, bir uygulamanın akışının kontrolünü geliştiriciden alıp, bu kontrolü çerçeve veya konteyner gibi dış bir kaynağa devretmeyi amaçlar. Bu durum, geliştiricinin sadece uygulama bileşenlerini oluşturup yapılandırmakla ve ardından çerçevenin bu bileşenleri yönetmesine izin vermekle sorumludur.
IoC’nin temel avantajlarından biri, yazılım bileşenlerinin daha az bağımlılık içermesi ve bu sayede değişikliklere daha dirençli olmalarıdır. Ayrıca, IoC’nin sunduğu bu esneklik, yazılım geliştiricilere daha geniş çaplı test yapma ve uygulamalarını daha kolay genişletme imkanı sağlar. Modern yazılım geliştirmenin temel ilkelerinden biri olarak, Spring ve benzeri çerçevelerde daha sürdürülebilir, okunabilir ve bakımı kolay kodlar oluşturmak için yaygın olarak kullanılmaktadır.
Dependency Injection (DI)
Dependency Injection (DI), yazılım geliştirmenin temel prensiplerinden biri olan Inversion of Control (IoC) içinde yer alan bir tasarım desenidir. Bir sınıfın dış bağımlılıklarını (dependencies) direkt olarak kendisi oluşturmak yerine, dışarıdan almasını sağlayan bir yöntemdir. Bu prensip, bir sınıfın diğer sınıflara olan bağımlılıklarını azaltarak, kodun daha esnek, bakımı daha kolay ve test edilebilir olmasına olanak tanır.
Bağımlılıkların dışarıdan verilmesi, test senaryolarında bu bağımlılıkların taklitleri (mocks) ile değiştirilmesini kolaylaştırır. Bu da yazılımın daha güvenilir ve hatasız olmasına katkı sağlar. Aynı zamanda, DI prensibi sayesinde kodun genişletilmesi ve bakımı daha rahat bir şekilde yapılabilir. Dependency Injection, yazılım geliştirmenin modern pratiklerinden biri olarak, özellikle büyük ve karmaşık projelerde yaygın olarak kullanılmaktadır.
Proje Kurulumu
Proje yapısı aşağıdaki gibi düzenlenmiştir.
selenium-boot-demo/
├── src/
│ ├── main/
│ │ └── java/com/example/seleniumboot/
│ │ └── SeleniumBootApplication.java
│ └── test/
│ └── java/com/example/seleniumboot/tests/
│ ├── BaseTest.java
│ └── GoogleSearchTest.java
├── pom.xml
Aşağıdaki bağımlılıkları “pom.xml” içerisine ekleyelim:
<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
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>selenium-boot-demo</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
</parent>
<dependencies>
<!-- Spring Boot Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- Selenium WebDriver -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.23.0</version>
</dependency>
<!-- WebDriverManager (sürücüleri otomatik yöneten kütüphane) -->
<dependency>
<groupId>io.github.bonigarcia</groupId>
<artifactId>webdrivermanager</artifactId>
<version>5.8.0</version>
</dependency>
</dependencies>
</project>Spring Boot başlangıç sınıfı oluşturulur. Bu sınıf yalnızca Spring Boot context’ini başlatmak için gereklidir. Testlerimiz @SpringBootTest anotasyonu üzerinden bu context’e bağlanacak.
package com.example.seleniumboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SeleniumBootApplication {
public static void main(String[] args) {
SpringApplication.run(SeleniumBootApplication.class, args);
}
}WebDriver Bean Tanımı (Config Sınıfı) oluşturulur. Burada Spring, WebDriver örneğini bir bean olarak yönetecek. destroyMethod = "quit" sayesinde testler bittiğinde tarayıcı düzgün biçimde kapatılacak.
package com.example.seleniumboot.config;
import io.github.bonigarcia.wdm.WebDriverManager;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class WebDriverConfig {
@Bean(destroyMethod = "quit")
public WebDriver webDriver() {
WebDriverManager.chromedriver().setup();
return new ChromeDriver();
}
}Test sınıfı oluşturulur, Bu sınıf, tüm testlerin ortak altyapısını sağlar. Spring Boot otomatik olarak WebDriver bean’ini enjekte eder.
package com.example.seleniumboot.tests;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.openqa.selenium.WebDriver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public abstract class BaseTest {
@Autowired
protected WebDriver driver;
@BeforeEach
public void setup() {
driver.manage().window().maximize();
driver.manage().deleteAllCookies();
}
@AfterEach
public void tearDown() {
if (driver != null) {
driver.quit();
}
}
}Örnek olarak google’da arama işlemi yaptıralım.
package com.example.seleniumboot.tests;
import org.junit.jupiter.api.Test;
import org.openqa.selenium.By;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class GoogleSearchTest extends BaseTest {
@Test
void googleSearchShouldReturnResults() {
driver.get("https://www.google.com");
driver.findElement(By.name("q")).sendKeys("Spring Boot Selenium\n");
assertTrue(driver.getTitle().toLowerCase().contains("spring boot selenium"));
}
}Aşağıdaki komutla testi çalıştıralım. Test çalıştırıldığında Spring Boot, ApplicationContext oluşturur, WebDriver bean’i üretir ve test tamamlandığında kapatır.
mvn testSonuç
Spring Boot ile Selenium WebDriver’ı birlikte kullanmak, sadece testlerinizi otomatikleştirmekle kalmaz; aynı zamanda proje mimarinize bağımlılık yönetimi, test verisi izolasyonu ve kolay bakım gibi profesyonel yazılım geliştirme prensiplerini de kazandırır. Bu yaklaşım sayesinde her bir test senaryosu, uygulamanın gerçek davranışını yansıtan birer mini modül haline gelir. Özellikle büyük ölçekli kurumsal uygulamalarda, Spring konteynerinin sunduğu “bean yönetimi” mekanizması testlerin sürdürülebilirliğini ciddi ölçüde artırır.
Bir başka önemli avantaj, konfigürasyon yönetiminin Spring tarafından üstlenilmesidir. Ortam bazlı (örneğin test, preprod, prod) yapılandırmalar, application.yml veya @PropertySource ile kolayca ayrıştırılabilir.
Bu sayede hem geliştiriciler hem de QA ekipleri aynı kod tabanı üzerinde farklı test ortamlarını rahatlıkla çalıştırabilir. Bu yaklaşım, DevOps süreçleriyle de tam uyumludur ve CI/CD boru hattına (özellikle Azure DevOps, Jenkins veya GitLab CI) kolayca entegre edilebilir.
Ayrıca Spring ile Selenium’un birlikte kullanımı, Page Object Model (POM) tasarım kalıbı ve JUnit 5 desteği sayesinde testlerin okunabilirliğini ciddi ölçüde artırır.
Her sayfa bir Java sınıfına, her aksiyon bir metoda dönüştüğünde kod hem daha anlaşılır hem de hataya daha dayanıklı hale gelir. Bu da yeni test senaryoları eklemeyi kolaylaştırır, bakım maliyetini düşürür.
Son olarak, bu mimari; Docker, Selenium Grid veya Kubernetes gibi modern altyapılarla ölçeklenebilir hale getirildiğinde, kurumsal seviyede bir test otomasyon ekosistemi oluşturmanın temellerini atar.
Bir sonraki adımda bu yapıyı CI/CD sürecine entegre ederek, her kod değişikliğinde otomatik olarak testlerin tetiklenmesini sağlayabiliriz. Böylece hem yazılım kalitesi yükselir hem de insan hatasından kaynaklı riskler minimize edilir.