Yazılım Testlerine Genel Bakış

“Bir musibet bin nasihatten iyidir” der atasözü. Bu söz, insanın dahil olduğu tüm süreçler için geçerlidir. İnsanın düşünme ve karar alma mekanizmalarının kusurlu oluşunu ima eder. İnsan, neyin ne kadar önemli olduğu, neyinse önemsiz olduğu ve gözardı edilebileceği konusunda sık sık yanılır. Hayat da bir tokat atıverir bir düzeltme faktörü olarak. Sonrasında oturur yerine taşlar.

Nasa, Aralık 1998'de Mars’a bir uydu gönderir. Uydunun iki görevi vardır. İlki Mars’ın iklim ve hava koşullarını incelemektir. İkinci görevi ise kendisinden 23 gün sonra gönderilen ve Mars’a iniş yapacak olan uzay aracı ile dünya arasındaki iletişimi sağlamaktır.

Eylül 1999'da uydu Mars’a yaklaşır ve uyduyu Mars etrafındaki nihai yörüngesine oturtacak komutlar gönderilir. Sonrasında “puff”. Uyduyla olan bağlantı kesilir ve uydu kaybolur. 2 gün boyunca uyduyla olan bağlantıyı kurmaya çalışırlar ancak tüm yoğun çabaya rağmen başarılı olamazlar.

Kazanın sebebini araştırmak üzere bir ekip kurulur. Anlaşılır ki kaza, kontrol merkezindeki yazılımlardan birindeki bir hatadan kaynaklanmıştır.

Nasa kontrol merkezinde uyduyu kontrol eden ve birbiriyle entegre çalışan uygulamalardan ikisi arasında iletilen değerlerin birimi ile ilgili anlaşmazlık hataya sebep olmuştur. Biri metrik sistemle çalışırken diğeri İngiliz sistemiyle çalışıyordur, spesifikasyon metrik sisteminin kullanılması gerektiğini söylediği halde.

Sisteme göre bir uygulama uzay aracının üzerindeki sensörlerin gönderdiği bilgileri alıp hız modellemesini ve simülasyonunu yapacak ve uydunun hareket yörüngesini ayarlayan diğer uygulamaya pervanelere uygulanması gereken gücü iletecektir.

Hız modelleme uygulaması, ilettiği dosyadaki değerleri İngiliz ölçü birimi ile (Pound) ifade edince, bu değerlerin metrik (Newton) olduğunu varsayan diğer uygulama uzay aracınının hızını olması gerekenden 4.5 kat daha az olacak şekilde ayarlar (1 Pound = 4.5 Newton). Bunun sonucu olarak uydu, tasarlanandan 170km daha fazla Mars’a yaklaşır ve kontrolden çıkıp yok olur.

Resim: Yanlış yörünge hareketi Kaynak: ftp://ftp.hq.nasa.gov/pub/pao/reports/1999/MCO_report.pdf

O dönemler Nasa’daki motto az zamanda az kaynakla çok şey yapmayı ifade eden “daha iyi, daha hızlı, daha ucuz”dur. 327 milyon dolarlık fiyasko Nasa’ya her şeyi yeniden gözden geçirmeye, sistemlerini ve süreçlerini düzeltmeye iter.

Yakın dönemden de bir çok örnek verilebilir. Hatalardan, karşılaşılan problemlerden ders alanlar kendilerini, süreçlerini düzeltmeye, sistemlerini o hatalara bağışık hale getirmeye çalışırlar. Ünlü bir örnek olarak Netflix, coğrafi olarak yedekli olan ve bir sürü servisten oluşan sistemini herhangi bir servisin herhangi bir lokasyonda çökmesine karşı bağışık kılmak ve bundan etkilenmemek üzere “kaos mühendisliği” ismini verdikleri bir pratiği uygulamaya koymuştur. “Kaos maymunu” ismini verdikleri bir uygulama her gün çalışma saatleri içerisinde rastgele bir servisi kapatır ve sistemin ayakta kaldığını her gün yeniden test ederler. Sistem kesintiye uğrasa bile problem çözme yetenekleri artmakta ve daha büyük problemleri gerçekleşmeden önce tespit edip önlem almaktadırlar. Böylelikle de sistemlerinin bu tür problemlere karşı dayanıklı olduğundan emin olmaktadırlar.

Tabi tüm uygulamaları aynı kefeye koymak mümkün değil. Hızlıca bir prototip oluşturup fikri test etmeye çalışan bir girişim ile oturmuş bir ürünü olan ve müşterilerine %99.9 oranında erişilebilirlik garantisini veren ve müşterileriyle hizmet seviyesi sözleşmesi (SLA) imzalamış bir şirketin yaklaşımı ve ihtiyacı aynı olmaz. İkisinin dertleri farklıdır, ikisi için önem sıralaması farklıdır.

Kurumsal uygulamalarda da hataya olan duyarlılık farklı olabilir. Direk son kullanıcıya ulaşan mobil uygulamadaki bir hata hem mali hem de kurum imajı açısından çok kritik olabilirken, kurum içinde kullanılmak üzere istatiksel raporlama yapan bir uygulamadaki bir hata, bir aksama görmezden gelinebilir.

Kurum için kritik olarak addedilen uygulamaların gerçek ortamda çok az hatayla, bulguyla çalışması önemlidir. Çünkü hatalar, finansal kayıplara, yasal yaptırımlara, kurumsal imajın zedelenmesine, ayrıca da verimsizliğe sebep olmaktadır. Çünkü hatalarla uğraşmak, en ön taraftan en arka tarafa kadar yatay ve dikeyde bir çok kişinin olaya müdahil olmasını, zamanlarını harcamalarını ve dikkatlerini kaydırmalarını gerektirir.

Bulgu sayısının az olması ise yazılımın kalitesi ve kaliteyi tescilleyen testlerle doğrudan ilgilidir.

Örneğin geliştirdiğiniz uygulama sunucusunun JavaEE sunucusu olarak Oracle tarafından tescillenmesini istediğinizde Oracle (daha önceleri Sun Microsystems), Java Compability Kit (JCK) ismini verdiği test suiti ile ürününüzü test eder ve eğer ürününüz tüm testlerden geçer ve tüm gereksinimleri yerine getirirse uyumluluk sertifikasını alırsınız. Glassfish, Weblogic, WebSphere, Wildfly(JBoss AS) vs. hepsi bu testlerden geçer. Yani kendi geliştirme süreçlerinin bir parçası olarak gereksinimler için (JSR) testler hazırlanır, ve bu testler hem referans uygulamanın hem de diğer şirketlerin ürünlerinin spesifikasyonlara uyumluluğunu test etmede kullanılır. Böylelikle belli bir kalite sağlanmış olur ve yüzler daha az kızarır.

Nasa hikayesindeki kök sebep entegrasyon testlerinin yapılmayışıdır. Sistemin farklı bileşenleri farklı şirketlere ait ekiplerce geliştirilmiş, her bir şirket kendi yazılımının testini yapmış ancak entegrasyon testlerinin yapılmayışı, bileşenlerin tencere-kapak misali uyumlu çalıştığından emin olamama sonucunu doğurmuştur. Bir diğer problem de uydunun yolculuğu süresince ortaya çıkan bazı semptomların gözardı edilmesidir. Ve sonuçta proje başarısızlıkla sonuçlanmıştır. Bir mıh bir nalı, bir nal bir atı, bir at bir komutanı…

Tanıklıklarım

İnsan alışkanlıklarının toplamıdır. Alışkanlarımız neyse oyuzdur. Alışkanlıklarımız değişince başka biri oluruz. Bu normal hayat için de böyledir, iş hayatı için de.

Her birimiz içinden geçip geldiğimiz süreçlerin ürünüyüz. Çalıştığımız şirketler, projeler bizim üzerimizde derin izler bırakırlar. Kazandığımız başarılarla, uğradığımız başarısızlıklarla, tecrübe ettiğimiz pratiklerle yontulur dururuz. Neyin çalıştığını, neyin işlemediğini tecrübelerimiz çerçevesinde öğreniriz. Önemsediğimiz ve önemsemediğimiz şeyler süreç içerisinde belirginleşir.

Geçtiğimiz yerlerdeki çalışma kültürleri bizim evrenimizi oluşturur. Referans ve dayanak noktalarımızı oluşturur. Çalışma biçimimizi oluşturur. Alışkanlarımızı oluşturur. Yazılım geliştiriciysek, yazılım geliştirme pratiklerimizi belirler.

Yazılım testleri bakımından farklı şirketler farklı pratiklere ve kültürlere sahip. Sadece kas gücüne dayalı manuel testlerle çalışanından, büyük oranda otomatize edilmiş testlere güvenenlerine kadar. Sarkaç bu ikisi arasında salınıp duruyor. Eğer otomatize testler yazılıyorsa ve bu testler hayat kurtarıyorsa insanlar onlara güvenmeye başlıyor ve bu testler bir koruma çemberi oluşturuyor. Eğer surlarda küçük bir gedik açılırsa bu güven zedelenmeye başlıyor ve insanlar manuel testlere geri dönmeye başlıyor.

Otomatik mi Manuel mi?

Eğer derdimiz yazılımın beklendiği gibi çalıştığını göstermekse ve eğer yazılımın her bir davranışını teker teker test edecek bir testçi ordumuz varsa teorik olarak manuel testler iş görebilir.

Pratikteyse, yapılan en küçük bir değişiklik sonrası tüm uygulamayı baştan başa test edecek testçi ordusuna sahip olmayız. Manuel testler belirli senoryaların test edilmesiyle sınırlı kalır. Daha önceden geliştirilmiş özelliklerden, fonksiyonlardan herhangi birini bozup bozmadığımızdan (regression) tam emin olamayız.

Sürekli entegrasyon (CI), sürekli teslimat (CD) pratiklerini uyguluyor ve kısa aralıklarla gerçek ortama taşıma yapıyorsak otomatize edilmiş testler “olsa iyi olur” değil “olması zorunlu olan”dır. Eğer ayda bir taşıma yapıyorsak manuel test edecek vaktimiz olur, ama haftalık, günlük gibi daha sık frekansta taşıma yapıyorsak kapsamlı test edecek vaktimiz olmaz. Yani arabanın tekerlekleri hızla dönmeye başlamışsa herhangi bir problemi anında tespit edip haber verecek uyarı sistemleri hayatidir. Manuel test arabanın fren yağını kendimizin kontrol etmesi gibidir, otomatik testse araç bilgisayarının bize bilgi vermesi gibidir. İkincisi daha konforlu, güvenlidir. İnsanlar unutur makineler unutmaz.

Otomatize testler, günlük işleyişte, eğer tadını almışsak bir daha vazgeçemeyeceğimiz şeyler sağlar bize:

  • Hızlı geribildirim: Daha kodu yazarken hızlı bir geribildirim mekanizması sağlar. Böylelikle bitti deyip teste gönderip, testçi test etmesini bekleyip, testçi test ettikten sonra bize şurada hata var demesini beklememiz gerekmez. İşi yaparken, başka bir işe geçmeden (context-switch), motor soğumadan hemen geri bildirim verir. Eklediğimi düşündüm yeni davranışın hakikaten çalışıp çalışmadığını hemen bilirim. Beklemem kimseyi.
  • Regresyon testi: Eski fonksiyonların bozulmadığından emin olma mekanizması verir. Bir şeyi bozduysam hemen haberim olur. En kötü ihtimalle göndermem yaptığım şeyi. Bozmam çalışan uygulamayı. Küçük bir uygulama, 5–10 kişilik küçük bir ekip için bu belki çok büyük probleme yol açmayabilir. Ama eğer içinde farklı bir sürü ekibin olduğu 200–300 kişi tarafından geliştirilen büyük bir kurumsal uygulamadan bahsediyorsak, farklı ekiplerin ortak kullandığı bir bileşendeki problem bir sürü ekibi etkileyecektir. Bir sürü ekibi durduracaktır. 5–10 birim değil 200–300 birim zaman kaybı olacaktır. Ölçek değişince kurallar da değişir. Ölçek değişince neyin önemli, neyinse önemsiz olduğu değişir.
  • Güven zırhı: Eğer uygulamanın farklı davranışlarını test eden bir testim varsa, bu bana kod değişikliği yapmada büyük bir güven verir. Kutunun içinde istediğim gibi at oynatırım. Bilirim ki dışarıdan bakıldığında bir değişiklik olmayacaktır. İstediğim gibi istediğim yere dokunur, değişiklikler, düzenlemeler yaparım. Eski koda dokunmaktan çekinmem, korkmam. Testlerin varlığı bana cesaret verir. Bu, testlerin verdiği güvene yaslanan bir cesarettir. Cesaretimin derecesi testlere duyduğum güvenle doğru orantılıdır.

Her şey, tüm fonksiyonların testi otomatize olur mu? Teorik olarak bu da mümkün. Ama pratikte zaman/kaynak vb. kısıtlar bizi sınırlar ve her bir kombinasyona test yazmayız. Testin kodu kapsama oranı genellikle 100% olmaz. Bazı şeylere otomatize test yazmak (mesela entegrasyonlar, asenkron şeyler vs.) çok pratik olmayabilir. Dolayısıyla her ne kadar otomatize edilmiş testlerimiz olsa da manuel olarak da bir test edip ekranın çalıştığını görmek isteyebiliriz.

Ayrıca belki ekranda oraya buraya rasgele tıklayıp, değer girip (maymun testi — monkey test) ekran sapıtıyor mu diye de bakmak isteyebiliriz.

Biraz Tarihçe

Araçlar, kavramlar, pratikler öyle bir anda pat diye ortaya çıkmazlar. Çağrışım ve etkileşimlerle ortaya çıkarlar. Süreç içinde gelişir, evrilir, farklı sentezler yaparak değişir dururlar. İşe yarıyorsa ayakta kalırlar, yaramıyorsa köpük gibi kaybolur giderler.

Yazılım testleri dünyasında bir sürü kavram ve araç var. Derdim bunlara bir genel çerçeve çizebilmek. Kısmen de olsa yakın dönemi tarihsel bir bağlama oturtabilmek. En azından bir çizgi üzerinden.

XUnit test kütüphane ailesinin doğuşu

Yazılım testlerinde kilometre taşlarından biri JUnit test kütüphanesinin (framework) ortaya çıkışıdır. 1994 yılında Kent Beck (XP, TDD) danışmanlığını yaptığı müşterisine test yazmalarını önerecektir, ancak ortada hazır kullanılabilecek Smalltalk için bir test kütüphanesi yoktur. O da SUnit test kütüphanesini yazar.

“Bir noktada bağımsız olarak danışmanlık verme yoluna gittim. Ve otomatize testlerin önemini fark etmeye başladım. Chicago’da bir müşteriye gideceğim ve onlara otomatize test yazmaya ihtiyaçları olduğunu söyleyeceğim. Ancak onlara otomatize testleri nasıl yazacaklarını nasıl söyleyeceğimi bilmiyordum. Uçağım kalkmadan önce programcılara aşina oldukları bir şekilde test yazmalarını sağlayacak bir araç oluşturabilir miydim? İki üç saat sonra şu an her yerde kopyası kullanılan bu XUnit kütüphanesinin (SUnit) ilk versiyonu oluşmuştu ve onu alıp müşteriye götürdüm ve onlara iyi bir danışman üslubuyla ‘test yazmanız lazım ve bu şekilde yazabilirsiniz’ dedim. ‘Kullanacağımız araç bu mu, tamam o zaman bu aracı kullanıyoruz’ dediler.” K. Beck

1997 yılında Eric Gamma (GOF, Design Patterns) Kent Beck ile bir konferansa giderken uçakta birlikte Junit’in ilk versiyonunu yazarlar. Eric Gamma testlerle ilgili bir şeyler öğrenmek, Kent Beck de şehrin yeni havalı çocuğu Java hakkında öğrenmek istiyordur. Birlikte 4 saatlik bir yolculukta hem test hem kod yazmak, Java kodunu Java ile yazılmış test kodu ile test etmek için Java test kütüphanesi JUnit’i yazarlar. Kodun yazıldığı dilde testi yazmak. Daha sonra bu test mekanizması, mimarisi diğer dillere de taşınmaya başlar. .NET için NUnit gibi. Aynı yaklaşıma sahip bu test ailesinden XUnit diye bahsedilmeye başlanır.

Ekstrem Programlama (XP) ve işin mutfağı

80'li yılların sonunda ve 90'lı yıllarda Kent Beck, Smalltalk topluluğunda önde gelen simalardan biridir. Ward Cunnigham (software patterns, wiki, xp) ile birlikte Tektronix şirketinde birlikte çalışırlar. Bu süre zarfında birlikte (pair) epey kod ve makale yazarlar. Kent farklı yerlerde Ward’ın kendisi üzerindeki etkilerinden ve onun mentorlüğünden bahseder.

İkili hakkında Eric Gamma, Kent Beck’in “Extreme Programming Explained — Embrace Change” kitabına yazdığı önsözde şöyle der: “Kent, karmaşık mühendislik uygulamarında birlikte (pair) çalışmanın potansiyelini farkeden Textronix’deki liderlerden biriydi. Ward Cunnigham ile birlikte, benim kariyerimde çok büyük etkisi olan tasarım kalıpları hareketinin en büyük ilham kaynağıdır.”

1996 yılında Chrysler firmasının C3 diye isimlendirilen ücret yönetim sistemi projesine danışmanlık vermek üzere davet edilir. Şirket bu projeyle, var olan uygulamayı modernize etmeye çalışmaktadır. Cobol’la yazılmış eski uygulamanın yerine geçmek üzere, Smalltalk ile yenisi yazılmaya başlamıştır. Ancak yeni sistemde bazı performans problemleri yaşanmaktadır. Kent, uygulamayı daha hızlı hale getirdiğimde çalışan fonksiyonların bozulmadığını gösterecek testleri görmek ister. Uygulamanın henüz tam çalışmadığını söylerler. “Eğer çalışması gerekmiyorsa, yazılımı gerçekten çok hızlı hale getirebilirim” der. Tabi komik bulmazlar bunu. Bir haftalık incelemenin sonunda Chrysler CIO’suyla görüşür ve ona, üç alternatifin olduğunu söyler. Ya bu şekilde devam edilecektir, ya proje bırakılıp bir dış firmaya ihale edilecektir veya çalışanlara bir hafta izin verip projeye sıfırdan başlanacaktır. CIO üçüncü seçenekle ilerlemeyi tercih eder ve projenin başına da Kent Beck’i getirir. O da bu projede, o güne kadar öğrendiği, tecrübe ettiği ve benimsediği pratiklerin hepsini bir arada uygulama ve sonuçlarını görme fırsatı bulur. Bunun sonucunda önemli çevik yazılım geliştirme metadolojilerinden biri olan Ekstrem Programlama (XP) doğar. Bu projede Kent, Ron Jeffries ile birlikte çalışmıştır. Martin Fowler da kısa bir dönem yarı zamanlı olarak bu projede yer almıştır.

XP proje yönetimiyle ilgili pratiklerin yanı sıra, kod kalitesini belirli bir seviyede tutmayı hedefleyen önce test sonra kod (TDD), kodun yeniden yapılandırılması (refactoring), sürekli entegrasyon gibi teknik pratikleri de içermektedir. Scrum vb. yaklaşımları kullanan ancak başarısızlıkla sonuçlanan bazı projelerle ilgili olarak Martin Fowler, yönetimsel pratiklere odaklandıkları ancak teknik pratiklere yeterli önemi göstermedikleri bunun sonucunda da kod kalitesinin düştüğünü ve kodun karmaşık ve yönetilemez hale geldiği eleştirisinde bulunur. XP pratiğini savunanlarca yapılan bir espriyi de belirtmeden geçmez: “Scrum, metodolojinin çalışmasını sağlayan teknik pratiklerinden sıyrılmış bir XP’dir sadece.” Buradaki problemi; Scrum ve benzeri yaklaşımların yetersizliğinde değil, bu yaklaşımların teknik pratikleri bilinçli bir şekilde göz ardı edip, belirtilmemesinden ve yönetimsel noktalara odaklanmasından hareketle teknik pratikleri önemsemeyen kullanıcılarda görür.

1999'da Kent, XP metodolojisini anlattığı “Extreme Programming Explained: Embrace Change” kitabını yayımlar. Bunu topluluktaki diğerlerinin yazdığı kitaplar izler ve metodoloji epey popülerleşir.

Önce Test (TDD) tekniği

Kent, otomatize testlerin adamıdır. Testçi adamdır. C3 projesinde uyguladığı XP metodolojisinde “önce test sonra kod” kuralını koymuştur. İlk olarak “Test-First Programming” olarak isimlendirdiği bu tekniği daha sonra “Test-Driven-Development” olarak değiştirmiştir.

Bu teknik temel olarak üç adımdan oluşur:

  • Önce ekleyeceğin fonksiyon için test ekle.
  • Sonra bu testi geçecek şekilde fonksiyonu yaz.
  • Kodun çalıştığını gördükten sonra onu yeniden yapılandır, düzenle, iyileştir, güzelleştir.

Bu üç adım TDD’nin mantrasını oluşturur: kırmızı-yeşil-yeniden yapılandırma (red-green-refactor).

Bu teknik, geliştiriciye birkaç fayda sağlamaktadır:

  • İlk olarak regresyon testlerini oluşmuş olur. Sonradan kod değiştirilirken güvenle değiştirilebilir. Kimse koda dokunmaktan korkmaz.
  • İkinci olarak kodu yazmadan önce kullanımını düşünmek, yazılacak sınıfın/modülün üzerinde kafa yormayı ve API’si üzerinden düşünmeyi sağlar. Bu da tasarımımızı yönlendirici ve kullanması kolay ve hoşa gidecek güzel API’ye sahip kod yazmamıza yardımcı olur.
  • Kod yazarken; oldu olmadı, bitti bitmedi, bozuldu bozulmadı dertleri, kod karmaşıklığıyla başa çıkmaya çalışmanın endişesi ve paniğini yönetmemize yardımcı olur. Önümüzü görmemizi sağlar. Kara uzakta bellidir. Testlerin geçmesi demek karaya ulaşmak demektir. Yani belirsizliği yönetmemize ve yönümüzü bulmamıza yardımcı olur. Karadan ne kadar uzakta olduğumuzu biliriz.

Fowler, bu tekniğin kendini test eden koda (SelfTestingCode) sahip olmanın bir şekli olduğunu söyler.

2002 yılında Kent Beck, TDD tekniğini anlatan kitabı “Test Driven Development: By Example” ı yayımlar.

Yüzeysel bir sınıflandırma

Yazılım testlerinin sınıflandırması konusunda farklı bir çok görüş var. Farklı isimlendirmeler ve farklı bakış açıları. Sınıflandırma konusunu daha sonra ele almak üzere bir kenara bırakalım, kaba bir sınıflandırmayla geçelim.

Fonksiyonel olmayan testler; performans, stres, kullanılabilirlik, güvenlik, ölçeklenebilirlik vb. testler olup, yazılımın fonksiyonel olmayan özelliklerini test ederler.

Birim testler geliştirici gözüyle yazılır. Geliştirici geliştirdiği sistemin parçalarının doğru çalışıp çalışmadığını, bir arada düzgün çalışıp çalışmadıklarını test etmek ve hızlı geri bildirim almak için birim test yazar. Birim test (unit test), geliştirici testi (developer test), bileşen testi (component test), entegrasyon testi (integration test), sistem testi (system test), servis testi (service test) ise aralarında kapsam ve odak farkı bulunmakla birlikte geliştiricinin yazdığı testlerdir.

Kabul testleri ise müşteri gözüyle yazılır. Yazılımın kabul kriterlerini sağlayıp sağlamadığını test eder. Kabul testleri, geniş kapsamlı testler (broad stack test), uçtan-uca-testler (e2e test), müşteri testleri (customer test), iş birimi gözüyle test (bussiness facing test), kullanıcı hikayesi testi (story test), kullanıcının ekrandaki bir yolculuğunun testi (journey test), fonksiyonel test; hepsi yakın anlamlıdırlar. Aralarında farklılıklar olmakla beraber hepsinin ortak özelliği müşteri gözüyle yazılmış olmalarıdır.

Kabul test otomasyonundan BDD’ye

2002 yılında, XP metodolojisinin kurucularından biri olan Ward Cunnigham, Excel benzeri tablosal bir notasyonla kabul testi yapan Fit aracını yayınlamıştır.

Resim: Fit — otomatize kullanıcı kabul testi aracı. Kaynak: http://fit.c2.com

2003 yılında Chris Stevenson, JUnit testlerinden otomatik teknik dokümanları oluşturan AgileDox aracını yazar. Aracın tüm yaptığı şey;

Kaynak:http://agiledox.sourceforge.net

şeklindeki bir JUnit testini alıp, en başta zorunlu olarak yer alan test kelimelerini atıp, normal okunabilir bir metne dönüştürmekten ibarettir. Ama etkisi büyük olmuştur.

Kaynak:http://agiledox.sourceforge.net

2003 yılında Robert C. Martin Fit ve Wiki araçlarını birleştirir ve FitNesse aracını oluşturur. Martin testlere spesifikasyon gözüyle bakar. Araç hem otomatize kabul testi yapmaktadır hem de kabul kriterlerini dokümantasyon olarak bir wiki web sayfası olarak yayınlar.

Bu dönemde kullanıcı/müşteri/iş birimi/analist, geliştirici ve testçi üçlüsünün bir araya gelerek önce kullanıcı hikayesinin kabul testinin yazıldığı sonra geliştirmesinin yapıldığı ATDD(Acceptace Test Driven Development) yaklaşımı ortaya çıkar. Bu yaklaşımı kullananlar Fit/FitNesse vb. araçları kullanırlar.

Resim: ATDD Test senaryo örneği. Kaynak: http://testobsessed.com/wp-content/uploads/2011/04/atddexample.pdf

Dan North danışmanlık verirken JUnit kütüphanesini kullanarak test yazmayı ve TDD tekniğini öğretiyordur. Ama programcılar nereden başlayacaklarını, neye test yazacaklarını, ne kadar test yazacaklarını, testleri nasıl isimlendireceklerini belirlemede güçlük çekiyorlardır. Chris Stevenson ona AgileDox aracını gösterdiğinde bir aydınlanma yaşar. Ve yavaş yavaş testleri müşteri gözüyle yazmaya, ifade etmeye başlar. Basit cümleler test senaryolarını daha anlaşılır kılmaktadır. “Açıklayıcı bir test ismi o test başarısız olduğunda yardımcı olur” der. “Test” yerine “Should” kelimesini kullanmaya başlar. Bu basit bir stilistik bir şey değildir, bir bakış açısı değişimi, paradigma değişimidir. “Should” (meli/malı) kelimesi kullanmaya başladığında insan zihninin sorgulamaya başladığını, “Olmalı mı, gerçekten mi?” diye sorgulamaya başladığını söyler.

“Testlerle düşünmekten davranışlarla (behaviour) düşünmeye geçmenin etkileri o kadar derindi ki TDD’ye BDD, behaviour-driven development demeye başladım.” Dan North

O sıralarda Eric Evans, Domain Driven Design (DDD) kitabını yayınlar. Temel fikir herkesin ortak bir dil konuşmasıdır. Yani günlük iş dilinin koda yansımasıdır. Martin Klepmann kurumsal dünyada çok iyi bilinen DDD kavramından internet tabanlı şirketlerde çalışanlarca bilinmediğini söyler. Çünkü kurumsal dünyadaki dert “işin, veri modelinin karmaşık olması” ve bu karmaşıklığın nasıl yönetileceği ile ilgilidir. Halbuki internet şirketlerinde ise ana problem “ölçekleme” problemidir.

Chris Matts (analist) ve Dan North (geliştirici) da bu sıralarda iş yerinde kullanılacak ortak bir dil yaratmakla meşguldürler. Çalıştıkları şirkette kullandıkları bir şablon oturmaya başlamıştır.

Bir [X] olarak 
[Y]’yi istiyorum 
böylece [Z]
X: Rol, Y: Özellik, Z: Elde edilecek fayda
(Kaynak: https://dannorth.net/introducing-bdd, çev: https://selimober.com/bdd-ye-giris/)

Kabul kriterlerini otomatize teste dönüştürebilecek ama çok da suni gelemeyecek bir forma sokmaya çalışırlar. Ortaya “Diyelim ki - Eğer ki - O zaman” (given-when-then) formatı çıkar.

Diyelim ki(Tanımlanan): şartlar, 
Eğer ki(Ne zaman): bir olay olunca, 
O zaman(Sonuç): sonuçları doğrula.
(Kaynak: https://dannorth.net/introducing-bdd, çev: https://selimober.com/bdd-ye-giris/)

Kullanıcı hikayesi şöyle bir şeye dönüşür:

+Başlık: Müşteri para çeker+ 
Bir müşteri olarak
ATM’den para çekmek istiyorum
böylece bankada sıra beklememe gerek kalmaz.
+Senaryo 1: Hesapta bakiye var+ 
Diyelim ki Bakiyesi olan bir hesap 
Ve kart geçerli 
Ve ATM’de nakit para var
Eğer ki müşteri para çekmek istediği zaman 
O zaman paranın hesaptan düştüğüne emin ol 
Ve paranın verildiğine emin ol 
Ve kartın iade edildiğine emin ol
(Kaynak: https://dannorth.net/introducing-bdd, çev: https://selimober.com/bdd-ye-giris/)

Bu şablonu kullanan JBehave kütüphanesini yazar Dan North. Ama test kodlarında hikayeler, henüz günümüzdeki Cucumber Gherkin dilinde (DSL: Domain Specific Language) olduğu gibi düz metin olarak (ör: .feature dosyaları) ifade edilmiyordur. Test hangi programlama dilinde yazılıyorsa o dilin kurallarına göre yazılıyordur.

RSpec proje lideri Dave Chelimsky, Dan North’un liderlik ettiği JBehave projesindeki söz dizimini (syntax) biraz değiştirip test kodlarındaki senaryoları parametrik olacak şekilde düz metin dosyalarına taşır. Bu büyük bir kırılım anıdır. BDD’nin tutunup yükselmesinde yardımcı olmuştur. Sonradan gelen Cucumber vb. araçlar bu yaklaşımı kullanmışlardır.

Dan North, birim test yazarken karşılaştığı problemlere çözüm başladığı yolda, BDD yaklaşımını ortaya koymuş, analist olan Chris Matts’in de katkısıyla, hikaye büyümüş, çıkış noktasını aşmış, yazılım analizinin merkezine doğru ilerlemiştir.

Birim test kütüphaneleri de bu yaklaşımdan etkilenmişler ve BDD stiliyle test yazmayı sağlayacak DSL’ler sunmuşlardır.

  • BDD stiliyle birim test örneği:
Resim: Go dilinde BDD stiliyle birim test. Kaynak: https://onsi.github.io/ginkgo
  • XUnit stiliyle birim test örneği:
Resim: Go dilinde XUnit stiliyle birim test. Kaynak: https://github.com/parnurzeal/gorequest/blob/develop/gorequest_test.go

Bitirirken…

Aslında yazmaya başladığımda hedefim testlere genel bir bakış sunmak, testlerin sınıflandırmasını yapmak ve mikroservisler özelindeki uygulamaları anlatmaktı. Ancak genel bir tarihçe ortaya koymaya çalışmak bile epey uzadı. Sonrasındaki teknik kısımlar bir başka bahara kaldı.

Kent Beck, “Ben harika bir programcı değilim. Ben sadece harika alışkanlıklara sahip iyi bir programcıyım” der.

Günümüzdeki test araçları test yazmayı epey kolaylaştırmaktadır. Ama tabi iş nihayetinde bireylerde bitiyor. Eğer insanlar testlerin işlerliğini, hayat kurtardığını görmüş, tecrübe etmiş ve günlük geliştirme rutinlerinin bir parçası haline getirmişlerse bu araçlardan faydalanırlar. Çünkü testler hızlı geri bildirim verir. Güven verir. Cesaret verir. Ortaya da bakımı nispeten daha kolay bir yazılım çıkar.

Ancak test yazmakla da iş bitmiyor. Testleri güzel, düzgün, anlaşılır yazmak, test kodlarına birinci sınıf vatandaş muamelesi yapmak gerekiyor. Gerektikçe test kodlarını düzenlemek, yeniden yapılandırmak gerekiyor. Aksi halde oralar da çöplüğe dönüşüveriyor. Yardımcı olmaktan çok aşağı doğru çekmeye başlıyorlar.

İyi alışkanlıklar edinmek bizim için iyi, bizim için faydalıdır. Bizim işimizi ve hayatımızı kolaylaştırır.

Son olarak, testlerin olması yazılımda hata çıkmayacağı anlamına gelmez. “Testler hatanın varlığını gösterir, yokluğunu değil” der E. W. Dijkstra.


Sözlük

Videolar

Kitaplar

Web Kaynakları

Notlar