Spring Boot Testing: Entegrasyon, Web, Güvenlik ve Selenium Testleri Nasıl Yazılır?
1. Neden Test Yazıyoruz?
Eğer test yoksa, Spring Boot uygulamanızın gerçek dünyada beklendiği gibi çalıştığından emin olmanız zordur. Testler; hem iş kurallarınızın doğruluğunu hem de refactor ve yeni özellik geliştirme süreçlerinin güvenliğini garanti altına alır.
- Doğrulama: Kodun doğru davranıp davranmadığını otomatik olarak kontrol eder.
- Regresyon koruması: Yeni özellik eklediğinizde mevcut fonksiyonelliğin bozulmadığını test eder.
- Güvenlik ağı: Uygulama ve mimari zaman içinde evrim geçirdikçe size güvenli bir geri bildirim mekanizması sağlar.
Unit test seviyesinde Spring çoğu zaman devrede olmak zorunda değildir; gevşek bağlılık ve arayüz odaklı tasarım, unit test yazmayı zaten kolaylaştırır. Ancak entegrasyon testlerinde Spring’in application context’ini yüklemesi ve bean’leri kablolaması kritik önem taşır.
2. Spring Boot ile Entegrasyon Testi
Spring Framework, uzun süredir SpringJUnit4ClassRunner ile entegrasyon testlerini destekler.
Spring Boot ise buna ekstra yetenekler ekleyerek entegrasyon test deneyimini zenginleştirir:
- Auto-configuration’ı testlerde de devreye alır.
application.properties/application.ymldosyalarını test context’ine yükler.- Spring Boot loglama ve konfigürasyonlarının çoğunu test ortamında da aktif hale getirir.
2.1. Temel Entegrasyon Testi Örneği
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = AppConfig.class)
public class AddressServiceTests {
@Autowired
private AddressService addressService;
@Test
public void testService() {
Address address = addressService.findByLastName("Sherman");
// assert'ler...
}
}
@SpringApplicationConfiguration, test context’ini tıpkı uygulamanın gerçek hayatta Spring Boot ile ayağa kaldırıldığı gibi yükler.
Böylece aynı yapılandırma, aynı bean’ler ve aynı özellikler testte de kullanılır; bu da testlerin gerçek ortama daha yakın olmasını sağlar.
3. Spring Boot Web Uygulamalarını Test Etme
Spring Boot ile yazdığınız web uygulamalarını test ederken iki yaklaşım öne çıkar:
- Mock MVC: Gerçek bir sunucu ayağa kalkmaz; Spring MVC mock’lanır. Çok hızlıdır.
- Web integration test: Uygulama gömülü sunucu ile gerçekten çalışır, testler gerçek HTTP istekleriyle koşar.
3.1. MockMvc ile Controller Testi
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ReadingListApplication.class)
@WebAppConfiguration
public class MockMvcWebTests {
@Autowired
private WebApplicationContext webContext;
private MockMvc mockMvc;
@Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders.webAppContextSetup(webContext).build();
}
}
Bu yapı sayesinde gerçek sunucu çalıştırmadan, HTTP isteği simüle ederek Controller’larınızı ve web katmanınızı test edebilirsiniz.
3.2. GET İsteği Örneği
@Test
public void homePage() throws Exception {
mockMvc.perform(get("/readingList"))
.andExpect(status().isOk())
.andExpect(view().name("readingList"))
.andExpect(model().attributeExists("books"));
}
3.3. POST İsteği Örneği
@Test
public void postBook() throws Exception {
mockMvc.perform(post("/readingList")
.contentType(MediaType.APPLICATION_FORM_URLENCODED)
.param("title", "BOOK TITLE")
.param("author", "BOOK AUTHOR")
.param("isbn", "1234567890")
.param("description", "DESCRIPTION"))
.andExpect(status().is3xxRedirection())
.andExpect(header().string("Location", "/readingList"));
}
Burada bir form POST isteği taklit ediliyor; parametreler ile form alanları dolduruluyor ve sonrasında redirect olup olmadığı ve Location header kontrol ediliyor. Böylece form işleme mantığı web katmanında baştan sona test edilmiş oluyor.
4. Spring Security ile Güvenlik Testleri
Güvenlik yapılandırılmış bir Spring Boot uygulamasında, testlerin de kimlik doğrulama ve
yetkilendirme kurallarını hesaba katması gerekir. Bunun için
spring-security-test modülü kullanılır.
4.1. Bağımlılık
// Gradle
testCompile "org.springframework.security:spring-security-test"
4.2. MockMvc ile Spring Security’yi Devreye Alma
@Before
public void setupMockMvc() {
mockMvc = MockMvcBuilders
.webAppContextSetup(webContext)
.apply(springSecurity())
.build();
}
4.3. Kimlik Doğrulama Anotasyonları
@WithMockUser– Belirtilen username, rol vb. ile sahte bir kullanıcı oluşturur.@WithUserDetails– TanımlıUserDetailsServicekullanarak gerçek kullanıcıyı yükler.
@Test
@WithUserDetails("craig")
public void homePage_authenticatedUser() throws Exception {
mockMvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(view().name("readingList"));
}
Bu sayede, farklı roller ve farklı kullanıcı tipleri için sayfalara erişim, HTTP statü kodları ve yönlendirmeler kolayca test edilebilir.
5. Gerçek Sunucuda Test: @WebIntegrationTest
Bazı durumlarda, Spring Boot uygulamasını gerçekten gömülü Tomcat/Jetty üzerinde ayağa kaldırıp
uçtan uca HTTP seviyesinde test etmek isteyebilirsiniz. Spring Boot, bunu
@WebIntegrationTest ile çözer.
5.1. Temel Örnek
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ReadingListApplication.class)
@WebIntegrationTest
public class SimpleWebTest {
@Test(expected = HttpClientErrorException.class)
public void pageNotFound() {
RestTemplate rest = new RestTemplate();
rest.getForObject("http://localhost:8080/bogusPage", String.class);
}
}
Bu testte uygulama ve gömülü sunucu birlikte ayağa kalkar ve RestTemplate ile
gerçek bir HTTP isteği atılır. Beklenen davranış 404 (veya başka bir client error) ise,
bunu HttpClientErrorException üzerinden doğrulayabilirsiniz.
5.2. Rastgele Portta Çalıştırma
Port çakışması yaşamamak için sunucuyu rastgele portta başlatmak da mümkündür:
@WebIntegrationTest(randomPort = true)
public class SimpleWebTest {
@Value("${local.server.port}")
private int port;
@Test
public void pageNotFound() {
RestTemplate rest = new RestTemplate();
rest.getForObject("http://localhost:{port}/bogusPage",
String.class, port);
}
}
6. Selenium ile Gerçek Tarayıcı (End-to-End) Testleri
RestTemplate veya MockMvc, HTML içeriğini test etmek için yeterli olsa da
gerçek kullanıcı deneyimini bire bir simüle etmez. Bu noktada
Selenium WebDriver devreye girer: gerçek bir tarayıcı açılır,
formlar doldurulur, butonlar tıklanır, sayfalar gezilir.
6.1. Bağımlılık
testCompile "org.seleniumhq.selenium:selenium-java:2.45.0"
6.2. Temel Selenium Test Şablonu
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = ReadingListApplication.class)
@WebIntegrationTest(randomPort = true)
public class ServerWebTests {
private static FirefoxDriver browser;
@Value("${local.server.port}")
private int port;
@BeforeClass
public static void openBrowser() {
browser = new FirefoxDriver();
browser.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
}
@AfterClass
public static void closeBrowser() {
browser.quit();
}
}
6.3. Form Doldurup Kitap Ekleme Testi
@Test
public void addBookToEmptyList() {
String baseUrl = "http://localhost:" + port;
browser.get(baseUrl);
browser.findElementByName("title").sendKeys("BOOK TITLE");
browser.findElementByName("author").sendKeys("BOOK AUTHOR");
browser.findElementByName("isbn").sendKeys("1234567890");
browser.findElementByName("description").sendKeys("DESCRIPTION");
browser.findElementByTagName("form").submit();
WebElement dl = browser.findElementByCssSelector("dt.bookHeadline");
// assert'ler...
}
Bu senaryoda test, gerçek bir kullanıcı gibi davranarak formu doldurur, gönderir ve sonrasında sonuç sayfasındaki verileri kontrol eder. Bu, Spring Boot uygulamaları için en gerçekçi uçtan uca test türüdür.
7. Genel Özet: Spring Boot ile Test Stratejisi
- Unit test için Spring çoğu zaman zorunlu değildir; ancak entegrasyon testlerinde Spring context hayati önem taşır.
@SpringApplicationConfigurationile testler de Spring Boot auto-configuration’dan faydalanır.- MockMvc ile hızdan ödün vermeden web katmanını test edebilirsiniz.
@WebIntegrationTestile uygulamayı gerçek gömülü sunucuda çalıştırıp HTTP seviyesinde entegrasyon testi yapabilirsiniz.- Güvenlik testleri için
spring-security-test,@WithUserDetailsve@WithMockUseranotasyonlarını kullanabilirsiniz. - Selenium ile tam uçtan uca (end-to-end) senaryoları gerçek tarayıcı üzerinden test etmek, kullanıcı deneyimine en yakın sonuçları verir.
Kısacası, Spring Boot yalnızca uygulama geliştirirken değil, test yazarken de size büyük kolaylık sağlar. Basit anotasyonlar ve zengin test araçları sayesinde, gerçek hayata çok yakın test senaryolarını pratik bir şekilde oluşturabilirsiniz.