Yazılım Test Süreçlerinin Önemi: Unit Test

Ümit Sayın
folksdev
Published in
5 min readMay 5, 2024

Merhaba arkadaşlar, bu yazımda yazılım geliştirme sürecinin kritik bir bileşeni olan test süreçlerinin önemini ele alacağım. Birlikte bu süreçlere göz atalım :)

Bir yazılım geliştirilirken, doğrudan özelliklerin test yazılmadan geliştirilmesi sonradan birçok büyük problem ortaya çıkarabilir. Bu tür problemler, zaman ve maddi olarak maliyetli olup, problemin tespitinin zor olduğu durumlarda kullanıcı deneyimini etkileyen büyük bir faktördür.

Örnek verecek olursak, yeni bir özellik geliştirdiğimizi düşünelim. Aylar sonra geliştirdiğimiz özellik başkası tarafından ek bir geliştirme ihtiyacı duyulduğunda mevcut kod yapısını bozup bozmadığını, sistemin hala bir bütün olarak çalışıp çalışmadığını ve davranışın değişip değişmediğini anlamamız zordur. Bu tür geliştirmelerde, geliştirilen kod Release ortamına çıktığında yeni eklenen kodun davranışı bozması durumunda ciddi maddi kayıp ya da kullanıcıların gözünde uygulamanın itibarını kaybetme gibi birçok problem ile karşılaşabiliriz.

Bu sorunları en aza indirgemek için test yazmamız en büyük önlemlerden biridir.

Neden Test Yazmalıyız?

Yazılım geliştirme sırasında, geliştirdiğimiz kodun davranışı dışında oluşan beklenmedik durumlar olabilir. Bu, olası hatalara “bug” adı verilir. Bu davranışların erken tespit edilmediği durumlar ciddi sonuçlara sebep olabilir. Yazılım üzerindeki beklenmedik herhangi bir davranış, kullanılan yazılımın itibarını, zaman ve maddi olarak büyük kayıpların yaşanmasına olanak sağlar.

Bir yazılım, testlerle desteklenerek geliştirildiğinde, mevcut kodda yapılacak herhangi bir değişiklik eğer testleri geçemiyorsa, bu durum erken aşamada tespit edilebilir. Bu sayede, eklenen yeni geliştirmelerin mevcut sistem davranışlarını bozup bozmadığı hızla anlaşılır. Eğer yeni geliştirme mevcut işlevselliği olumsuz etkiliyorsa, yazılan kod testleri geçecek şekilde düzenlenir. Öte yandan, eklenen kod sisteme yeni özellikler ekliyorsa, mevcut testler bu yeni duruma uygun olarak güncellenmelidir. Bu yaklaşım, yazılımın istikrarını ve güvenilirliğini korumak için kritik öneme sahiptir.

Test yazmak birçok avantaj sağlar. Bunlardan bazıları şunlardır:

  • Hataları erken aşamada tespit etmeye yardımcı olur, böylece daha büyük sorunların önüne geçilir.
  • Yazılımın kalitesini ve kullanıcının güvenini artırır.
  • Sistem performansını iyileştirir, böylece yazılım daha hızlı ve verimli çalışır.
  • İhtiyaç dışı geliştirmelerin önüne geçerek zaman ve kaynak israfını önler.
  • Geliştirme süreci boyunca yazılıma dair değerli dokümantasyon sağlar ve bu bilgiler yeni geliştiricilere rehberlik eder.

Test Yaklaşımları

Test Yaklaşımları, yazılım geliştirme sürecinde uygulanan farklı test stratejilerini ifade eder. Bu yaklaşımlar, yazılımın kalitesini artırmak, hataları erken aşamada tespit etmek ve geliştirme sürecini daha verimli hale getirmek için kullanılır. İşte yazılım testlerinde kullanılan bazı yaygın yaklaşımlar:

  • Unit Testing: Birim testi, yazılım geliştirme sürecinde, bir programın en küçük test edilebilir parçalarının bağımsız olarak doğru şekilde çalışıp çalışmadığını kontrol etmek için kullanılan bir test yöntemidir.
  • Acceptance Testing: Kabul testi, yazılımın iş gereksinimlerini ve kullanıcı beklentilerini karşılayıp karşılamadığını değerlendirmek için kullanılır. Bu testler genellikle ürünün son kullanıcıya teslim edilmeden önce yapılır.
  • Integration Testing: Entegrasyon testleri, yazılımın farklı bölümlerinin veya modüllerinin bir arada doğru bir şekilde çalışıp çalışmadığını kontrol etmek için yapılır. Bu testler, modüller arası bağlantıların ve veri akışlarının doğru şekilde işlediğini doğrular.
  • Performance Testing: Performans testi, yazılımın belirli bir yük altında nasıl performans gösterdiğini ölçer. Bu testler, yazılımın tepki sürelerini, işlem kapasitesini ve kaynak kullanımını değerlendirir.
  • Security Testing: Güvenlik testi, yazılımın güvenlik açıklarına karşı ne kadar güvende olduğunu değerlendirmek için kullanılır. Bu testler, yazılımın yetkisiz erişimlere ve saldırılara karşı korunup korunmadığını test eder.

Birçok test yaklaşımı bulunmakta ve bu yaklaşımlar, yazılım geliştirme süreçlerinin önemli bir parçasını oluşturmaktadır. Yazının geri kalanında, geliştiricilerin yazılım üzerinde çalışırken yazmaları gereken unit testleri ele alacağız.

Unit Test

Unit testler, yazılımın en küçük parçalarını test etmek için yazılan otomatik testlerdir. Bu testler, genellikle kodun her bir fonksiyonunu veya metodunu, belirli girdilerle çağırarak ve beklenen çıktıyı doğrulayarak gerçekleştirilir.

Yazılım geliştirilirken, mümkün olduğunca çok parçalara ayrılmalıdır. Herhangi bir metod eklendiğinde, metodun davranışı tutarlı olmalıdır. Bir metodun birden fazla davranışı gerçekleştirmesi, Solid prensiplerinin Single Responsibility prensibine aykırıdır. Geliştirilen yazılım birçok parçadan oluşmalı ve her parça birbirinden bağımsız, kendi davranışı ile ilgilenmelidir.

Unit test yazarken en önemli kısım, yazılacak metodun davranışını tam olarak temsil etmesidir. Metodun davranışı dışında gerçekleşen bir test, amacının dışına çıkmış ve faydasız bir testtir. Bu yüzden, mümkün olduğunca metodun davranışını kapsayan testler yazmalıyız. Test yazarken önemli bir diğer nokta ise test için kullanacağımız veridir. Bu veri ne kadar gerçeğe yakın olursa, test amacına o kadar ulaşmış olur. Ayrıca, bu oluşturulan test verisi, test edilecek kod ile birlikte bir dokümantasyon sağlar. Takımınıza yeni bir geliştirici geldiğinde, metodun anlaşılması için testin girdilerine ve çıktılarına bakabilir; bu da yeni bir geliştiricinin yazılım üzerinde adaptasyonunu hızlandırır.

Unit Test Yazarken Dikkat Edilmesi Gerekenler

  • Her test, tek bir senaryoyu test etmelidir.
  • Bir test, başka bir teste bağımlı olmamalıdır.
  • Test edilen metot yalnızca tek bir işlevi yerine getirmelidir.
  • Test isimleri açık ve açıklayıcı olmalıdır, böylece testin amacı hemen anlaşılabilir.
  • Test verileri ve girdileri dikkatlice seçilmeli ve çeşitli senaryoları kapsamalıdır.
  • Test edilen metot, sadece metodun davranışını temsil etmelidir ve gereksiz karmaşıklıktan kaçınılmalıdır.

Sık Kullanılan Unit Test Frameworkleri

  • JUnit (Java): Java dilindeki unit testleri için en popüler framework.
  • NUnit (.NET): .NET platformunda kullanılan bir unit test frameworkü. C#, VB.NET ve F# gibi .NET dillerinde unit testleri yazmak için kullanılır.
  • Mocha (JavaScript): JavaScript dilinde yaygın olarak kullanılan bir test frameworküdür. Hem tarayıcıda hem de Node.js ortamında çalışabilir.
  • TestNG (Java): JUnit alternatifi bir Java test frameworkü.

Şimdi de birlikte unit test yazalım :) Örneğin elimizde ismine göre kategori getiren bir servisimiz var.

Basitçe düşünmek gerekirse, unit test yazmadan önce serviste test edilmesi gereken senaryoları belirleyelim. Öncelikle, herhangi bir sorun yaşanmadığı bir senaryo, kategorinin bulunamadığı bir senaryo ve kategorinin doğru şekilde eşleştirilemediği senaryoları ele alalım.

Burada dikkat etmemiz gereken bir nokta var. Mapper işlemi, bu metod üzerinde ne kadar çok senaryo olsa da, mapper testlerini ayrıca yazmalıyız. Bunun sebebi, bu mapper işleminin farklı yerlerde kullanılabilir olması ve her seferinde mapper senaryosunun testini yazmamız gerekliliğidir. Unit testler yazılırken, testlerin birbirinden bağımsız olması gerektiği için Mapper testlerini ayrı bir şekilde yazalım. :)

Öncelikle test için gerekli olan setup metodunu oluşturmalıyız. Setup metodu, test edilecek servisin bağımlılıklarının mocklanması gibi test öncesi gerekli ihtiyaçların karşılandığı metoddur.

Yukarıda dikkatli baktığımızda, test etmek istediğimiz metodun her iki senaryosunun da test edildiğini görebiliriz. Test isimlendirmelerimiz açıklayıcı ve amacına hizmet edecek şekilde verilmiş; sadece isme bakarak neyin test edildiğini ve sonucun ne olduğunu anlayabiliriz.

Öncelikle ilk testi inceleyelim.

İlk olarak, test için gerekli olan verileri oluşturduk; bu veriler, test bağımlılıklarını yönetmek veya test edilen servis metodunda karşılaştırma yapmak için kullanılır.

İkinci olarak, metodumuz CategoryRepository’e bağımlı olduğu için, mockladığımız categoryRepository ile findByName metodunu çağırıldığında döndürmek istediğimiz Category sınıfını veriyoruz. Bu sayede bağımlılığın davranışının sonucunu belirlemiş oluyoruz.

Üçüncü olarak ise, test etmek istediğimiz servisin metodunu tetikleyip, assertEquals ile servisin döndürdüğü response ile beklediğimiz response'un kontrolünü yapıyoruz.

Son olarak, verify metodu ile bağımlılıkların doğru şekilde kullanıldığından emin olmak için bağımlılığın hangi davranışını kaç kere kullandığımızı doğruluyoruz.

Diğer test ise, tekrar bağımlılığın davranışını belirleyerek, kategorinin bulunmadığı durumda bir istisna fırlattığını kontrol eden test metodunu geliştirmiş olduk.

Benzer şekilde, mapper testini de yazabiliriz. Yukarıda belirtilen test verilerini oluşturduktan sonra, MapStruct ile mapleme yaptığımız metodun testini gerçekleştirebiliriz.

Bu yazımda Yazılım Test Süreçlerinin Önemi üzerine özellikle Unit Test’leri ele aldım. Umarım faydalı bulmuşsunuzdur. Sonraki yazılarda görüşmek üzere, sağlıcakla kalın!

--

--