Test Otomasyon’a Yeni Bir Bakış: Nested Page Object Model
Test otomasyonu dünyasında, testlerin bakımı ve sürdürülebilirliği en büyük zorluklardan biri. Burası tam da Page Object Model’in (POM) devreye girdiği yer. POM, test otomasyonu projelerinde kodunuzu daha temiz ve düzenli tutmanın harika bir yolu. Peki bu model tam olarak ne yapıyor ve nasıl çalışıyor? Daha da önemlisi, neden artık POM bizimi için yeterli değil ve Nested Page Object Model’e geçmek istiyoruz. Bu iki model arasındaki farklar nelerdir? Gelin, birlikte keşfedelim.
Page Object Model (POM) Nedir?
Page Object Model, basitçe her bir web sayfasını veya bileşeni, ayrı bir sınıf olarak temsil eden bir Design Pattern(Tasarım Deseni)’dir. Burada amaç, sayfadaki tüm etkileşimlerin o sayfaya özgü bir sınıf tarafından yönetilmesidir. Örneğin, bir giriş sayfasının formu, butonları, metin kutuları gibi tüm bileşenleri “LoginPage” adlı bir sınıfla yönetilir. Bu sayede test kodları ile sayfa bileşenleri birbirinden ayrılmış olur. Test senaryolarında sayfa elemanlarını direkt çağırmak yerine, bu sınıfın metodları ile çağırıyoruz. Böylece, bir sayfadaki değişiklik sadece ilgili sayfa sınıfında güncellenir, test senaryolarında ise hiçbir şey değiştirmeye gerek kalmaz. Bu da bize testlerin bakımında büyük kolaylık sağlar.
POM’un Avantajları:
- Tekrar Kullanılabilir Kod: Aynı sayfa elemanlarını farklı testlerde tekrar tekrar kullanabiliyoruz.
- Bakım Kolaylığı: Web sitesinde bir değişiklik mi oldu? Sadece ilgili Page Object’te güncelleme yapıyorsun, hepsi bu kadar.
- Okunabilirlik: Test kodları daha temiz ve anlaşılır oluyor.
Page Object Model’in Tıkandığı Noktalar
Gitgide Karmaşıklığı Artan Sayfa Yapıları
POM’un bize sağladığı en büyük avantaj her sayfaya ait bir sınıf oluşturulması ve sadece o sayfaya ait element ve metotların yer alması. Bu yapı sayesinde farklı sayfaların kodları ayrı sınıflara ayrılmış oluyor. Kodları bir nevi kategorize etmiş sayılıyoruz.
Çok güzel bir yapımız var ancak çok önemli bir sorunumuz da var. Projemiz büyüdükçe daha fazla case yazıyoruz ve o sayfaya ait daha fazla element ve metot olmuş oluyor. Yeri geldiği zaman bir sayfa için 1500–2000 satıra kadar kod yazılabiliyor. Buda bize gitgide sayfaların karmaşıklığını artmasına sebeb oluyor.
Kod Tekrarının Minimize Edilemesi
POM aslında bazı kod tekrarlarının önüne geçmesini sağlıyor ve bize çok güzel avantajlar sunuyor. Ancak bazı durumlarda kod tekrarını engelleyemiyor.
Bazı durumlarda bir sayfada yer alan bir komponent başka bir sayfada da yer alabiliyor. Bu durumda her iki sayfada da aynı komponent için tekrar kod yazmak durumda kalabiliyoruz. Base sınıflar kullanarak bu durumun önüne kısman geçmek mümkün olsada ileriki aşamada Base sınıfının da şişmesine sebeb olucaktır. Bundan dolayı kod tekrarları yaşayabiliyoruz.
Kod Bakımı (Maintenance) ve Güncellemeler
Bir yazılım projesinin kod yazım aşamasında göz önünde bulundurulması gereken en önemli etmenlerden biri de bakımdır. Bir projenin bakımının zor olması projenin büyüdüğü zaman çok büyük sorunlar yaşamasına sebeb olur ve projede ilerleme hızını düşürür.
Daha demin de bahsettiğim gibi Page Object Model yapısını kullandığımız zaman projemiz büyüyüp karmaşıklaşınca projenin bakımı da bir o kadar zorlaşır. Düşünsenize sayfanızda bir değişiklik oldu ve otomasyonunuzu bu yeni özelliğe göre değiştirmeniz gerekiyor. Ancak büyük bir sorunumuz var. Değiştirmek istediğimiz sayfanın sınıfı 1500–2000 satırdan oluşuyor. 250–300 adet web element var. Doğru yere odaklanmak ne kadar da zor. Hatta değiştirilmesi gereken yerin birden fazla sayfada geçen bir komponent olduğunu bir düşün. İşte o zaman çok basit olan bir kod güncellemesi çok zor bir bakım sürecine girmiş oluyor.
Nested Page Object Model Nedir?
Nested Page Object Model’de moduler bir yapıya geçiş yapmış oluyoruz. POM gibi her sayfa için ayrı bir sınıf oluşturuyoruz. Farklı olarak sadece sayfaları değil sayfaların içindeki bölümleri de parçalara ayıracağız. Bu şekilde olabildiğince kodu parçalamış olucaz ve parçaladığımız yapı başka bir sayfada kullanılıyorsa onu orada da kullanıyoruz. Böylelikle hem kod karmaşıklığını azaltmış olucaz hem de kod çoklamalarının önüne geçmiş olucaz.
Bu diagram’ı incelediğimiz zaman POM ve Nested POM arasındaki farkı daha net görüyoruz. POM’da her sayfa için bir sınıf varken Nested POM’da her sayfa için bir sınıf artı olarak sayfa içindeki komponentler için de ayrı sınıflar olucak.
Uygulama: Nested Page Object Model
Evet Teorik kısım biraz sıkıcı olabilir. Asıl iş uygulama tarafında. Bundan dolayı sizlerle beraber bir uygulama yapalım. Böylelikle Nested Page Object’in faydalarını görmüş olucaz.
1. Komponentlerin Yazımı
İlk adım olarak hangi sayfayı test ediceksek o sayfayı belli komponentlere ayırmak gerekiyor. Ben örnek olarak HangiKredi Ana sayfayı test etmek istiyorum. Yukarıdaki görselde gördüğünüz gibi HK Anasayfayı 4 ayrı parçaya böldüm ve Header için test case yazmaya başlıyoruz.
public class Header extends BaseComponent {
// Web Elementler
@FindBy(id = "header")
HKWebElement header;
@FindBy(css = ".login")
HKWebElement loginButton;
@FindBy(css = ".hellobar")
HKWebElement helloBar;
@FindBy(css = ".navigation li")
List<HKWebElement> navigationElements;
// Metotlar
public void checkLinkRedirectsToCorrectUrl() {
navigationElements.forEach(element -> {
var linkUrl = element.getLinkUrl();
element.click();
var currentUrl = getDriver().getCurrentUrl();
Log.pass("Expected: " + linkUrl);
Log.pass("Actual: " + currentUrl);
Assert.assertEquals(currentUrl, linkUrl);
getDriver().navigate().back();
});
}
}
Öncelikle Header diye bir sınıf oluşturdum ve içine sadece Header’da bulunan web elementleri ekledim. Header sınıfını BaseComponent diye bir sınıftan extend ettim. İlk baktığınızda BaseComponent ve HKWebElement ne diye sormuş olabilirsiniz. Bunlar bizim HangiKredi içerisinde geliştirdiğimiz ve Selenium’daki PageFactory’inin gelişmiş hali diyebiliriz. Burası için ayrı bir yazı yazacağım ve detaylı açıklamasını yapacam. Onun için bu tarafı geçiyorum şimdilik.
2. Sayfaların Yazımı
public class HomePage extends BasePage {
@FindBy(css = "header")
public Header header;
}
Komponentimizi oluşturduktan sonra sıra test yapılacak sayfa için bir sınıf oluşturmada. Biz Ana Sayfayı test edeceğimiz için HomePage diye bir sınıf oluşturup BasePage’den extend ettim. Klasik otomasyon testleri yazarken FindBy anotasyonunun altına WebElement eklenirdi. Biz burda web element yerine bir komponent ekledik. Artık HomePage sınıfı header komponentine sahip.
3. Test Sınıfın Yazılması
@Epic("HangiKredi")
@Feature("Home Page")
@Story("Header")
public class HeaderTests extends BaseTest {
@Test
public void checkHeaderLinksRedirectCorrectly() {
getPage(config.hkBaseUrl(), HomePage.class)
.header
.checkLinkRedirectsToCorrectUrl();
}
}