Unit Test Nedir? Kotlin’de JUnit’i Nasıl Uygularız?

Mehmet Fethi Mese
Delivery Hero Tech Hub
5 min readAug 24, 2022

JUnit testing

Unit test deyince yapsak çok iyi olur diye düşünürüz. Fakat sonra zaman kısıtımızdan veya farklı faktörlerden dolayı, kodumuzu önce yazalım daha sonra zaman kalırsa testini de yazarız şeklinde bir eğilimimiz olur. Kodlarımızı yazdıktan sonra ise geriye dönüp baktığımızda o kadar çok şey yazmış oluruz ki, şimdi bunların testlerini yapmakla kim uğraşacak diye düşünürüz 😅 Hadi bir yerden başlayalım sonunu getiririz deriz. Ama bu sefer de yazdığımız kodlar test etmemizi engeller ve test yapabilmek için kodlarımızı değiştirmeye başlarız. Kodların değişimi çok fazla olunca ve zaman kısıtı da varsa ya test yazmaktan vazgeçeriz ya da az sayıda unit test yazmakla yetinmek durumunda kalırız 😤.

Peki unit test yazmak gerçekten zaman alıcı ve zor mu? Neden unit test yazmak için ayrıca efor harcıyoruz? 🤔 Bu yazımda, öncelikle unit test nedir ve ne işimize yarar bunu anlamaya çalışacağız. Sonrasında test demişken TDD’den bahsetmeden geçemeyeceğim. Son olarak Kotlin’de JUnit kullanımına ve pratiklerine bir göz atacağız.

Unit test (birim testi) iş akışı içerisindeki her bir akışın ayrı ayrı test edilmesi demektir. Unit test’lerimiz en başta kod hatalarımızı minimize etmeye yarar. Aynı zamanda daha temiz ve anlaşılır kodlar yazmamızı sağlar. Diğer taraftan uygulamamız daha sürdürülebilir hale gelir. Yani daha önce test edilen test durumlarını, kod içerisinde değişiklik yaptıktan sonra tekrar tekrar test etme şansına sahip oluruz. Bu sayede herhangi bir test case durumunu atlamamış oluruz.

TDD (Test Driven Development) nedir?

Test denildiğinde TDD kavramı çok büyük öneme sahiptir. TDD bir tür kaliteli ve sürdürülebilir geliştirme yapma yaklaşımıdır. Unit testlerimizi TDD (Test Driven Development) yöntemiyle yapmamızın bize bir çok avantajı bulunmaktadır. TDD sayesinde hem daha temiz kod yazmış oluruz hemde code coverage’mizi artırarak hatalarımızı minimize etmiş oluruz. TDD önce test sonra development anlamına gelmektedir. Bunun için aşağıda gördüğünüz resimdeki yöntem uygulanmaktadır. Önce test methodu yazılır. Test başarısız olur sonrasında test başarılı hale getirilir. Daha sonra mevcut tüm testlerin başarılı olması sağlanır. Son olarak, kod refactor edilerek temiz hale getirilir.

TDD sayesinde üst katmandan alt katmana doğru kod yazma eğiliminde bulunabiliriz. Bu yolla, önce client isteklerini sonrasında ise business, database ve entegrasyon kısımları ayrı ayrı test edebiliriz. Öncelikli olarak client isteklerinin gereksinimleri karşıladığımız için business ve diğer tüm katmanlarda daha doğru bir development ve test yapmış oluruz. Ayrıca her katmanı ayrı ayrı testlerden geçirerek daha yalıtık bir test ortamı hazırlamış oluruz.

TDD (Test Driven Development)

JUnit kütüphanelerinin Kotlin’de uygulanması

JUnit ise java dünyasında en çok kullanılan test kütüphanelerden bir tanesidir. JUnit sayesinde unit testlerimizi rahat ve hızlı bir şekilde yapabiliyoruz. Gelin şimdi JUnit kavramlarına ve uygulama kısmına birlikte bakalım. Aşağıda bulunan kodlar Kotlin 1.3.41 ve JUnit 5.4.2 versiyonlarını içermektedir.

JUnit annnotation’lar kod tekrarı yapmadan etkili bir şekilde test yapmamıza imkan sunmaktadırlar. JUnit jupiter api dokümanlarına ayrıca link üzerinden erişebilirsiniz. Hadi gelin beraber bu annotation’lara birikte bakalım.

  • @Before (Bazen değişkenleri önceden tanımlamaya ihtiyacımız olabilmektedir. Bu tür durumlarda test çalışmadan hemen önce yapılacak işlemleri before annotation altında yapabiliyoruz. Her test methodu çalışmadan önce before çalışmaktadır.)
  • @Test (Çalıştırmak istediğimiz methodun başına konulan bir annotation’dır. Tüm birim testlerimizin başına bu annotation’ı koyarak test methodlarımızı çalıştırırız.)
  • @MockK (Mock nesnesi oluşturarak için kullanıyoruz. Nesneleri istediğimiz şekilde set etmemizi sağlar. Bu sayede testi geçebilmek için bazı nesnelere değer atama yapabiliriz.)
  • @Nested (Bir sınıf içerisinde başka sınıfları nested olarak işratleyebiliyoruz. Bu sayede testlerimizi çalıştırdığımızda, birbiriyle alakalı testleri içeren daha yapısal bir çıktı görebiliriz.)
  • @KotlinParameterizedTests (Sınıf içerisinde farklı parametreleri vererek aynı testin her bir parametre için tekrar tekrar koşmasını sağlamaktadır.)
  • @ParameterizedTest (Test methodumuzun parametrik değerlere bağlı olarak her bir parametre için ayrı ayrı çalışmasını sağlar.)
  • @MethodSource (Test methodu içerisinde test edilecek parametrik değerleri içeren fonksiyonun ismini alarak mapping yapmaktadır.)
  • @CsvSource (Method içerisinde kullanılacak parametrik değerleri içermektedir. MethodSource yerine alternatif olarak bu yöntemde kullanılabilmektedir.)
  • Assertions (Yapılan testlerin doğruluğunu kontrol etmek için kullanılmaktadır. Assertions.assertDoesNotThrow, Assertions. assertTrue şeklinde bir çok kullanım alanı bulunmaktadır. link )
  • Kluent (Assertions gibi testleri doğrulamak için kullanılmaktadır. Test okuması daha kolay olduğu için tercih edilebilir. `should throw` veya should contain`vs. şeklinde kullanımları bulunmaktadır. link üzerinden kluent dokümanına erişebilirsiniz.)

JUnit kullanımı ve annotation’lar

Unit test methodlarının anlaşılır bir şekilde isimlendirilmesi çok önemlidir. Çünkü hangi test case’in geçip hangisinin geçmediğini method isimlerinden anlayabiliyoruz. İsimlendirme yaparken 2 yöntem bulunmaktadır. Bunlardan birincisi method isim kurallarına uygun bir şekilde yazılması. İkincisi ise back tick `` işareti içerisinde arada boşluk bıraklarak yazılması. Daha anlaşılır olmasından dolayı en yaygın kullanımı ikinci yöntemdir. Aşağıdaki kod bloğunu inceleyerek annotation’ların kullanım şekillerini görebilirsiniz.

Test yazması zor olan durumlar

Bazı testlerin yazılması gerçekten zor ve zaman alıcı olabilmektedir. Özellikle TDD yöntemi ile yazılmayan testlerde çok karşılaşılan third party componentlerin test edilmesi veya bunların mock’lanması problemlere neden olabilmektedir. Genel olarak karşılaşılan tarih bilgisi içeren veya dosya işlemi yapılan iki durumun testini aşağıda anlatmaya çalışacağım.

Tarih bağımlılık testi nasıl yapılır?

Date ve Time değişkenlerini iş akışımız içerisinde kullanmaya ihtiyacımız olabilir. Tarih değişkeni sürekli değişkenlik gösterdiği için iş akışını her yeniden başlattığımızda aynı sonucu almamız mümkün olmamaktadır. Peki bu tür durumdaki bir iş akışını nasıl test edebiliriz?

Aşağıdaki kodu incelerseniz getLogDate() methodu içerisinde kullanılan todayDate değişkeni method içerisinde set edildiği için bu değişkene dışarıdan müdehale etmemiz mümkün olmamaktadır. todayDate değişkenine bağlı sonuç üreten method ise her çağrımda farklı bir sonuç döner. Peki getLogDate() methodunu nasıl test edebiliriz? Bu methodu test edilebilir hale getirmek için getLogDate(todayDate:DateProvider) şeklinde parametre geçerek yazmamız gerekmektedir. todayDate değişkenini dışarıdan parametre olarak almalıyız ki bu değişkene dışarıdan müdahale ederek testimizi yapabilelim. Bu nedenle DateProvider şeklinde bir interface ihtiyacımız olacaktır. Gördüğünüz gibi test ederken aynı zamanda yapılan yanlış bir geliştirmeyi de düzeltmiş oluyoruz ve test edilebilir hale getirmiş oluyoruz.

Dosya veya database gibi üçüncü parti kullanım testleri nasıl yapılır?

Dosya’dan okuma yazma işlemi yapan bir methodu test yapmak istediğimizde, Kotlin içerisindeki concrete File nesnelerini method içerisinde direkt olarak kullanmak bizim bu methodu test etmemizi gerçekten zor duruma sokacaktır. Methodu test edilebilir hale getirmek için ayrı bir File sınıfı oluşturmamız ve ilgili method’a parametre olarak inject etmemiz gerekmektedir.

Aşağıdaki kod bloklarını incelerseniz, Logger sınıfı içerisinde bizim iş akışımız bulunmaktadır. Logger sınıfı constructor içerisinde bizim ayrıca oluşturduğumuz Configuration, Paths ve Files gibi sınıfları parametre olarak almaktadır. Burada alınan parametre değerleri iş akışı içerisinde kullanılmaktadır. Bu sayede artık Logger sınıfı içerisindeki dosya işlemlerini LoggerTest sınıfında gördüğünüz üzere test edebilir hale getirdik.

Son

Bu yazımda unit test nedir ve Kotlin’de junit nasıl yazılır anlatmaya çalıştım. Unit test yazmanın, uygulamamızdaki hataları minimize ettiğini, kalitesini arttırdığını ve uygulamamızın sürdürülebilirliğini sağladığını gördük. Ayrıca, junit ile unit testlerimizi nasıl yapabileceğimizi anlatmaya çalıştım. Zaman ayırdığınız ve yazımı okuduğunuz için teşekkür ederim. Bir sonraki yazımda görüşmek üzere…👋

--

--