top of page

Selenium Hibrit Otomasyon Çerçevesini Java'dan Python'a Taşımak

selcukgenc
3 saat önce
6 dakikada okunur

Selenium Hibrit Otomasyon Çerçevesini Java'dan Python'a Taşımak

Anahtar kelime tabanlı bir çerçeveyi yeni bir dilde yeniden kurarken öğrendiklerim

Test çerçevesi taşımayı anlatan yazıların çoğu işin kolay kısmında durur: findElement, find_element olur; anotasyonlar dekoratöre dönüşür ve iş biter. Bu bir taşıma değildir; yanına bir blog yazısı iliştirilmiş bir bul-değiştir işlemidir.

Hibrit çerçeve bambaşka bir yapıdır. Bir anahtar kelime katmanı, tablolarla yönetilen bir veri katmanı, bir nesne deposu, bir raporlama motoru, genellikle bir veritabanı tarafı ve çoğu zaman programcı olmayanların çalıştırabilmesi için üstte küçük bir arayüz barındırır. Bunu Java'dan Python'a taşımak bir çeviri işinden çok, sabit bir şartnameyle yapılan yeniden inşadır — ve o şartname, yıllardır kimsenin baştan sona okumadığı bir kod tabanıdır.

Aynı başlangıç çizgisinde duran herkese şunları söylerdim.

Birinci kural: satırları değil, davranışı taşıyın

Satır satır birebir aktarım cazip gelir. Güvenli hissettirir ve kolay incelenir. Oysa ne güvenlidir ne de iyi bir incelemedir; çünkü Java'nın alışkanlıklarını Python'a taşır — orada gürültü gibi okunurlar — ve Java'nın hatalarını da beraberinde getirir; üstelik artık kimsenin bulamayacağı bir Python kılığında.

Hedef, dışarıdan bakıldığında birebir aynı davranan, Python'a özgü (idiomatic) bir kod olmalı. Bu iki hedef sürekli çatışır ve her çatışma bilinçli olarak vermeniz gereken bir karardır.

Anahtar kelime yönlendirmesini ele alalım. Java'daki bir hibrit çerçeve anahtar kelimeleri genellikle yansıma (reflection) ile çözer: metodu adıyla bulur, çağırır, dönen metne bakarak başarılı mı başarısız mı olduğuna karar verir. Argümanlar sürücü sınıfındaki paylaşılan durum üzerinden gelir.

Bunu Python'da da kurabilirsiniz. Çalışır. Ama yanlış tercihtir; çünkü Python size dekoratör tabanlı bir kayıt mekanizmasını hazır sunar: anahtar kelimeler içe aktarma (import) sırasında kendilerini kaydeder, motor onları bir sözlükte bulur ve argümanlar paylaşılan, değiştirilebilir global değişkenler yerine açık bir bağlam (context) nesnesiyle taşınır. Tablo açısından davranış aynıdır. Hata ayıklayıcı açısından ise çok daha iyidir.

Bir taşımadaki her iyi kararın biçimi budur: sözleşmeyi koru, mekanizmayı değiştir. Sözleşme, test yazarlarının gördüğü şeydir — tablo sütunları, anahtar kelime adları, locator deposu, rapor. Altındaki her şeyi yeniden tasarlamakta özgürsünüz.

Asıl iş nerede

Çerçeveniz yalnızca butonlara tıklıyorsa taşıma bir hafta sonu işidir. Geri kalan zamanı üç alan tüketir.

Veri katmanı

Doğrulama sorguları, temizleme rutinleri, rapor üreticileri — eski Java çerçevelerinde bunlar genellikle sınıf gövdesine dağılmış metin birleştirmeleriyle, değerler cümlenin ortasına eklenerek yazılmıştır. Bunları ayıklamak projenin tek başına en büyük parçasıdır. Ayıklamak için bir araç yazarsanız şunu unutmayın: kodu kalıplarla okuyan her araç, size sessizce yalnızca tanıyabildiği kısmı verir. İnceleme süresini yalnızca aracın bulduklarına değil, bulamadıklarına da ayırın. Hatalar sessizdir: iki ifade çalıştıran bir metot tek ifadeymiş gibi taşınır ve yapması gereken ikinci iş bir anda yapılmaz olur.

Tür doğruluğu

En az hazırlıklı olduğum alan buydu ve en pahalı hataları da o üretti — pahalıydı, çünkü çerçeve çalışmaya ve yeşil rapor vermeye devam ediyordu. Java'nın JDBC katmanı neredeyse her şeyi metin olarak verir; Python sürücüleri ise gerçek türleri döndürür. Boolean bir veritabanı sütunu bir dilde metin, diğerinde gerçek bir boolean olarak gelir; onu sayı gibi ayrıştıran kod artık genel bir catch bloğuna düşer ve bütün bir doğrulama yolunu sessizce atlar. Yüksek hassasiyetli zaman damgaları Python'un datetime türünden geçerken bir basamak kaybeder; her zaman eşleşen bir eşitlik karşılaştırması artık hiç eşleşmez. Tablo kütüphaneleri de size saklanan değeri mi yoksa görüntülenen değeri mi verdikleri konusunda farklılık gösterir. Bunların hiçbiri kendini belli etmez.

Selenium'un kendi bağlamalarındaki (binding) farklar

İstemciler birebir aynı değildir. Klasik örnek bir öznitelik okumaktır: hangi çağrıyı kullandığınıza bağlı olarak DOM özelliğini, W3C uç noktasının tanımladığı değeri ya da HTML'deki birebir değeri alabilirsiniz — kendi spesifikasyonlarına göre üçü de doğru olan üç farklı cevap; eski Java bağlaması ise dördüncü bir cevap döndürmüş olabilir. Bir Java çağrısı ile bir Python çağrısı farklı sonuç verdiğinde, fark genellikle Selenium'da değil, DOM'un hangi katmanını okuduklarındadır. Başarısız her karşılaştırmada elementin outer HTML'ini loglayın; bu tek teşhis yöntemi bu tartışmaların çoğunu günler yerine dakikalar içinde çözer.

Bir uyuşmazlığı yok etmek için karşılaştırmayı asla gevşetmeyin

Bunu ayrı bir başlık altında anlatmam gerekiyor, çünkü bu hatayı yaptım ve yakalandım.

Birebir aynı olması gereken iki değer aynı değildi. Nedenini araştırmak yerine karşılaştırıcıyı esnek hale getirdim ve satırlar eşleşmeye başladı. Eşleşiyorlardı, çünkü çerçeveye bir hatayı kabul etmeyi öğretmiştim.

Esnek bir karşılaştırıcı, özellik rütbesine terfi ettirilmiş bir hatadır. Aynı olması gereken iki değer aynı değilse, bir şey bulmuşsunuz demektir. Gidin ve ne olduğunu öğrenin.

Biri başarılı geçen bir koşuya bakıp ekrandaki değerlerin neden hâlâ farklı göründüğünü sordu. O soru, geçersiz kıldığı günlerce süren emekten daha değerliydi.

Test otomasyonu için Java mı Python mu: dürüst bir karşılaştırma

Genel olarak doğru cevap tek bir dil değildir. Farklı ekipler için farklı diller doğru cevaptır.

Özellik

Java

Python

Yazım hızı

Ayrıntılı; her soyutlamanın etrafında kalıp kod

Yazması ve değiştirmesi belirgin şekilde daha hızlı

Güvenlik ağı

Derleyici yazım hatalarını, imza kaymalarını ve ölü kodu çalıştırmadan önce yakalar

Hatalar çalışma anında ortaya çıkar — çoğu zaman uzun bir test paketinin derinliklerinde

Yeniden düzenleme (refactoring)

Mükemmel, IDE destekli, büyük kod tabanlarında güvenli

Yapılabilir ama daha riskli; testlere ve linter'lara çok dayanır

Geliştirici olmayanların öğrenmesi

Zor — derleme araçları, JDK sürümleri, proje yapısı

Kolay — çoğu manuel test uzmanı okuyup düzenleyebilir

Eşzamanlılık

Gerçek thread'ler; paralel yürütme çözülmüş bir sorun

GIL thread'leri kısıtlar; paralellik süreç (process) ya da grid demektir

Başlangıç ve çalışma maliyeti

Geç başlar; uzun süren CPU yoğun işlerde daha hızlıdır

Hızlı başlar; testler G/Ç ağırlıklıyken nadiren darboğaz olur

Ortam kurulumu

Her makinede JDK; daha ağır ama çok standart

Tek yorumlayıcı, tek requirements dosyası; sanal ortamlar bir adım ekler

Teknik olmayan kullanıcılar için paketleme

Olgun, öngörülebilir JAR dağıtımı

Tek bir çalıştırılabilir dosyaya paketlemek mümkün ama daha sivri köşeleri var

Ekosistem uyumu

Kurumsal araçlarda, derleme hatlarında ve raporlama paketlerinde en güçlü

Veri, dosya, API ve hızlı yapıştırıcı kodda en güçlü

Uzun vadeli bakım

Türler dokümantasyon işlevi görür; büyük ekipler uyumlu kalır

Bilinçli disiplin ister — ölçek büyüdükçe type hint ve linting isteğe bağlı değildir


Dürüst özet: Java sizi kendinizden korur; Python yolunuzdan çekilir. Otomasyon ekibiniz yıllar boyunca büyük, ortak bir kod tabanını sürdüren geliştiricilerden oluşuyorsa, Java'nın derleme zamanı güvencesi ayrıntılı yapısına değer. Ekibiniz çoğunlukla bu öğleden sonra yeni bir anahtar kelime eklemesi gereken test uzmanlarından oluşuyorsa, Python'un okunabilirliği derleyicinin sağladığı her şeyden daha değerlidir.

İnsanların önemli olacağını düşündüğü ama olmayan iki şey: ham çalışma hızı (tarayıcı testlerinde zamanı diliniz değil, sayfa beklemeleri belirler) ve kütüphane bulunabilirliği (her iki ekosistem de Selenium, Excel, veritabanları ve raporlamayı gayet iyi karşılar).

İnsanların hafife aldığı bir şey: dağıtım sorunu. Bunu bazıları kilitli olan yirmi makineye kurmak zorunda kalan kişi, ikisi arasındaki farkı test yazan herkesten daha çok hisseder.

Taşıma bir denetimdir — buna göre planlayın

Büyük bir kod tabanını, davranışını birebir yeniden üretmek amacıyla satır satır okumak, o kod tabanının alacağı en kapsamlı kod incelemesidir. Benimki, yıllardır canlıda olan uzun bir hata listesini ortaya çıkardı: beklenen ve gerçek değeri hesaplayıp sonra hiç karşılaştırmayan doğrulamalar; sıfır dosyayla eşleştiğinde başarı bildiren döngüler (hiç indirilmemiş bir rapor başarılı bir dönüştürme gibi görünüyordu); iki yönde de yanlış çalışan bir görünürlük yardımcısı; asla doğru olamayacak bir yeniden deneme koşulu; kaynak kodda duran kimlik bilgileri.

Bunların hiçbiri onu yazan kişiye yönelik bir eleştiri değil. Teslimat baskısı altında on yıl boyunca büyüyen her çerçevenin başına gelen budur. Ama projeye bakışınızı değiştirir: yalnızca bir çerçeveyi taşımıyorsunuz, onu denetliyorsunuz. İlerledikçe taşımadan ayrı bir hata günlüğü tutun ve bunu hâlâ orijinal çerçeveyi kullanan ekibe verin — o hatalar bugün canlı ortamda.

Madalyonun öbür yüzü — ki buna altı ayrı kez çarptım: bir şeyi “engellendi, daha fazla bilgi gerekiyor” diye ilan ettim ve altı seferde de orijinal kaynağı düzgünce okumak, elimdekilerle taşınabilir olduğunu gösterdi. Bir şeyin imkânsız olduğunu söylemeden önce kodu okuyun.

Beni defalarca kurtaran iki çalışma alışkanlığı

Her düzenlemeden sonra uzun süre çalışan süreci yeniden başlatın. Çalışan bir sunucu ya da arka plan servisi, başlangıçta içe aktardığı modülleri tutar. Bir keresinde bir düzeltmenin diskte olduğunu, zaman damgasının koşudan önce olduğunu doğruladım ve yine de hiçbir etkisi olmadı — çünkü süreç eski sürümü doksan saniye önce yüklemiş ve bir daha bakmamıştı. Zaten doğru olan bir düzeltme yüzünden bir akşamın büyük kısmını kaybettim. Düzenle, yeniden başlat, sonra tekrar test et. Her seferinde.

Biçime değil, ifadeye tutunun. Bir rutin, ekrandaki bir cümleden bir sayıyı çekiyordu. İlk kalıbım sayının uzun olduğunu varsayıyordu ve daha kısa bir sayı çıktığı anda başarısız oldu. Orijinal kod ise çevresindeki ifadeye tutunuyor ve her uzunluğu karşılıyordu. Metinden veri çıkarıyorsanız metni eşleştirin — verinin neye benzediğine dair varsayımınızı değil. Aynı içgüdü test otomasyonunun her yerinde geçerlidir: bir şeyi, onu yazdığınız gün nerede durduğuna göre değil, ne olduğuna göre bulun.

Değdi mi?

Evet — ama iş gerekçesindeki nedenlerle değil.

Python çerçevesi daha küçük, daha okunaklı, tek komutla kuruluyor ve artık her test uzmanının makinesinde JDK gerektirmiyor. Yeni anahtar kelimeler eklemek çok daha kısa sürüyor ve Java'ya asla dokunmayacak test uzmanları artık Python'u rahatça düzenliyor. Vaat edilen faydalar bunlardı ve geldiler.

Vaat edilmeyen fayda daha büyüktü. Yıllarca süren sessiz bir kaymanın ardından nihayet biri her satırı okudu. Taşıdığınız bir çerçeve, anladığınız bir çerçevedir — hiç çalışmamış olan kısımları da dahil; ki bu, çoğu ekibin varlığından bile haberdar olmadığı bir kategoridir. Python'da testlerin çalışma süresi de Java'ya göre çok daha kısa.

Bunu herkese önerir miyim? Hayır. Java çerçeveniz sağlıklıysa, iyi anlaşılıyorsa ve ekibiniz Java'ya hâkimse, taşıma daha çok sevdiğiniz bir sözdizimini satın almanın pahalı bir yoludur. Bunu dil gerçekten bir engel olduğunda yapın — onu sürdürmesi gereken insanlar ya da üzerinde çalışması gereken makineler için. Bunlar iyi nedenlerdir. “Python daha popüler” ise değildir.

Ve başlarsanız: veri katmanı için bütçe ayırın, ayıklama araçlarınıza güvenmeyin, bir karşılaştırmayı asla yumuşatmayın ve geride bıraktığınız çerçeve için bir hata günlüğü tutun.

Taşıma, denetimin ta kendisidir. Tek başına bu bile neredeyse maliyetini karşılar.

 
 
 

Yorumlar


bottom of page