Bu makalemizde, yazdığımız basit bir fonksiyonun test kodunu Jasmine ile nasıl yazabileceğimizi göreceğiz. Jasmine ile birlikte çalışmak için, öncelikle ihtiyaç duyduğumuz kütüphanesini Github Download sayfasından indirmemiz gerekiyor.


Ben bu makaleyi yazarken yayında olan son sürüm 1.3.1'di. İlgili linke tıklayınca bir zip dosyası inecektir. İnen zip dosyasını açtığımız takdirde, karşımıza aşağıdaki gibi bir görüntünün gelmesi gerekiyor.



Bu klasör düzeni aslında, Jasmine tarafından tavsiye edilen proje klasör yapısıdır. Bu yapıya göre bizim yazdığımız kodlar "src" klasörü altında, yazacağımız test kodları "spec" klasörü altında, kullandığımız dış kütüphaneler de "lib" klasörü altında bulunur. "SpecRunner.html" dosyası ise, testlerimizi çalıştırıp sonuçlarını görebilmemiz için gerekeli olan sayfadır.

Not : Elbette bu dizin yapısını değiştirmekte özgürüz. Bu durumda tek yapmamız gereken, "SpecRunner.html" dosyası içerisindeki adresleri yeni dizin yapısına göre değiştirmektir. Bu seni korkutmasın, çünkü 50 satırlık bir HTML belgesindeki 6 satırı değiştirmekten bahsediyoruz.

İşin aslı, indirdiğimiz bu zip dosyası içerisinde örnek olarak beş test metodu yazılmış ve hepsi çalışır durumdadır. Ama onlar yetiyor olsaydı, bu makaleyi neden okuyor olasın, değil mi :) Haydi o zaman, vakittir. Kolları sıvayıp kendi kodumuzu yazalım.

Hayal ediyoruz...

Müşterinin biri bizi aradı ve bir ihtiyacının olduğunu söyledi. Kaynak yetersizliği sebebiyle, yeni yetme, işe yeni aldığımız junior bir analisti müşteriye gönderdik. Müşteri de dedi ki, "Benim bir fonksiyona ihtiyacım var. Dışarıdan iki tane parametre alacak ve bunları toplayıp bana geri dönecek". Müşteriye bak hizaya gel :)

Tabii bizim analist sevinçten uçuyor. İlk işi ve çok kolay bir talep. Hemen atladı arabasına, döndü şirkete ve bu ihtiyacı bize söyledi. Bir de ilk fırçasını afiyetle kaydık. Neden?

Bir kere onun yerine senior bir analist gitseydi, müşterinin tuttuğu takımdan, evlilik yıl dönümüne, hatta eşinin burcuna kadar her şeyi öğrenmeden geri gelmezdi. Hadi, bir junior analistten bu kadarını da beklemiyorduk ama yukarıdaki istekten en az 20 tane soru çıkardı be kardeşim. İş bu kadar olsa, talebi telefonla da alırız, sana niye maaş verelim, değil mi?

Mesela hangi sorular sorulabilirdi?
  • Fonksiyon sadece tam sayıları mı kabul edecek, yoksa küsüratlı sayılar da kabul edilecek mi?
  • Çıktı tam sayı mı olacak, yoksa küsüratlı olabilir mi?
  • Eğer küsüralı olacaksa, virgülden sonra kaç basamağa kadar küsürat isteniyor?
  • Eğer tam sayı olacaksa, küsürat hangi tarafa yuvarlanacak?
  • Diyelim ki iki parametreye de "a" ve "b" değerleri geçildi. "ab" şeklinde alfabetik birleştirme mi yapılacak, hata mı fırlatılacak, "undefined" değeri mi dönülecek, yoksa sayısal karşılık olarak 0 cevabı mı dönülecek?
  • Diyelim ki ilk parametre olarak "a", ikinci parametre olarak 5 geçildi. Beklenen cevap "a5" midir? 5 midir? "undefined" mıdır?
  • Fonksiyonun dönmesi istenen en küçük (sonsuz küçük) ve en büyük (sonsuz büyük) sınırları nelerdir?
  • Fonksiyon senkron mu çalışacak, yoksa asenkron çalışıp cevabı callback fonksiyonuna mı geçecek?
  • Fonksiyonun adı ne olacak?
  • Fonksiyon AMD modülü şeklinde mi, yoksa klasik mi yazılacak?

Uzatmayalım, kassak bir bu kadar daha soru çıkar ama fırçayı kaydık, bir daha yapmaz inşallah. Biz de aldık talebi, yine kaynak yetersizliği sebebiyle junior bir yazılım geliştiricinin önüne koyduk. O da sağolsun, fırça yeme öncesinde aşağıdaki gibi bir kod yazdı.

"use strict";

function add(val1, val2) {

    return val1 + val2;

}

Neyse ki, test tarafında bir kaynak sıkışıklığımız yoktu ve filmimiz başladı.

Not : Burada BDD tarzında yazılım geliştirmeyi anlatmıyorum. Eğer öyle olsaydı, talepler test ekibinin önüne gider, onlar taleplere uygun test kodunu yazar, sonrasında da yazılım ekibi testleri başarılı hale getirecek kodları yazmaya çalışırlardı. Bu makalede sadece Jasmine ile test kodu nasıl yazılır, onu öğreniyoruz. BDD yaklaşımı için ayrı bir makale yazacağım inşallah.

Öncelikle test ekibindeki arkadaş biraz söylendi, çünkü hem müşteri talebi, hem de yukarıdaki kod eline iki ayrı mail ile geçti. Ne proje klasör yapısı, ne dokümantasyon. Ama an itibariyle performans değerlendirme dönemi içerisindeydi ve pürüz çıkartmak istemedi. Masaüstüne, proje adı olan "TestSample" isimli bir klasör oluşturdu. İçine de "src", "spec", "lib" ve "doc" isimli dört klasör oluşturdu. Bu noktada test ekibindeki arkadaşın masaüstünde bulunan klasörün görünüşü aşağıdaki gibiydi.


Müşteri talebini içeren mailde yazanları, ki şu anda tek bir cümle, "doc" klasörü altına "Project Specs.txt" adıyla bir dokümana kaydetti. Böylece Source Control'den projeyi çeken herkes, proje ile ilgili dokümanlara rahatlıkla ulaşabilecekti.

Ardından yukarıda Jasmine sitesinden indirdiğimiz zip dosyası içerisinde bulunan "lib" klasöründeki "jasmine-1.3.1" klasörünü, direk buradaki "lib" klasörünün içerisine yapıştırdı.

Sonrasında, junior developer tarafından kendine mail ile gönderilen kodu, "src" klasörü altına "program.js" adıyla kaydetti.

Kendi yazacağı testler için kullanacağı dosyayı da, "spec" klasörü altında "programSpec.js" ismiyle oluşturdu.

Geldiği son noktada, masaüstündeki dosya ve klasör yapısı aşağıdaki gibi oldu.


Sıra geldi testleri yazmaya. Burada filme 5 dakika mola verelim ve bir ara bilgilendirme geçelim.

Jasmine ile test yazmak için öncelikle yazılan uygulamayı modüller/bölümler/sınıflar şeklinde düşünmemiz gerekiyor. İdealde (burada src klasörü altında bulunan) kodlama tarafında yazılan her bir sınıf, ayrı bir dosyada yer almalıdır. Her bir sınıfa karşılık yazılan (burada spec klasörü altında bulunan) test kodları da, o sınıfın test kodlarını içerdiğini gösteren bir notasyon ile isimlendirilmelidir. Jasmine tarafında bunun genel kabul kabul görmüş şekli, "SınıfIsmiSpec.js" şeklindedir. Gerçi burada yazılmış bir sınıftan bahsedemeyiz, bizim velet tek bir fonksiyon yazmış ama dosya ismi "program.js" olduğu için, test dosyasının ismini de "programSpec.js" olarak verdik.

"Spec.js" dosyaları, Jasmine'de test kodlarımızı yazdığımız dosyalardır. Biz bu dosyalara çeşitli fonksiyonlar yazarız ve her bir fonksiyon, programın farklı bir yerini test ederek, beklendiği gibi davranıp davranmadığını test eder. Herhangi bir "Spec.js" dosyasının en ilkel halini aşağıda görmekteyiz.

"use strict";

describe("Test edilecek işi/sınınfı anlatan birkaç kelime", function () {

});

Burada metinsel içerik elbette Jasmine için bir anlam ifade etmez ancak çıktıyı sayfaya bastığında, bizim nelerin doğru, nelerin ters gittiğini anlamamız için önemlidir. Birazdan filmimize döndüğümüzde daha iyi anlayacaksın inşallah.

En basit halini yukarıda gördük ancak maalesef bu hali hiçbir işe yaramaz çünkü içerisinde herhangi bir test fonksiyonu bulunmuyor. Eğer bu test kodunun içerisine bir test fonksiyonu yazmak istersek, en basit haliyle aşağıdaki kodu elde ederiz.


İşte bu, tek bir test fonksiyonunu içeren bir test kodudur. Ne var ki, fonksiyonun içerisi boş olduğu için herhangi bir şeyi test etmez ve her zaman başarılı sonuç verir. Demek ki işimiz bitmedi ama az kaldı. Testi gerçekleştirmek için, Jasmine ile birlikte gelen "expect" ve "toEqual" gibi fonksiyonları kullanırız. Hemen bir örnek üzerinde görelim.


Yukarıda görülen test kodu tamamlanmıştır ve her zaman başarılı sonuç verir (Burada belirtilen iki değerin eşit olup olmadığı kontrol edilir). Bu şekilde istediğimiz kadar test fonksiyonunu alt alta yazarak testlerimizi sıralayabiliriz.

Ara bitti, filme devam.

Test ekibindeki arkadaş, "programSpec.js" dosyasının içerisine aşağıdaki kodları yazıyor.


Şimdilik tek bir test fonksiyonu oldu ama çalışıp çalışmadığını görmek istiyor. Bunun için yapması gereken son bir şey kaldı. Jasmine ekran çıktısı için gerekli olan HTML belgesini hazırlamak. Bunu da direk "TestSample" klasörünün altına "SpecRunner.html" adıyla ve aşağıdaki içerikle kaydediyor (Ki bunu da aslında kendi yazmıyor, az önce indirdiğimiz zip içerisindeki HTML belgesini alıp değiştiriyor).


Hepsi bu kadar. Testin sonucunu görmek için HTML belgesini açıyor ve aşağıdaki görüntüyle karşılaşıyor.



Güzel. Yeşil olduğuna göre şimdilik her şey yolunda (Yazılan metinsel ifadelerin ne işe yaradığını da artık daha iyi anlamışsındır).

Sonrasında test bölümündeki arkadaş, analisti arıyor ve sayısal olmayan değerler girildiğinde müşterinin fonksiyondan nasıl bir çıktı beklediğini soruyor. Analist de telefon ile müşteriyi arayıp soruyor ve öğreniyor ki, "Sayısal olmayan tüm değerler '0' olarak kabul edilmeliymiş". Örneğin "a" + 5 = 5 veya "a" + "b" = 0 gibi. Müşteri her zaman haklıdır, diyecek bir şey yok.

Bunun üzerine test ekibindeki arkadaş, konu hakkında ikinci bir test fonksiyonunu test koduna ekliyor ve "programSpec.js" dosyasının son hali aşağıdaki gibi oluyor.


Test etmek için "SpecRunner.html" sayfasını açıyor ve aşağıdaki sonuçla karşılaşıyor.


Hmm. Bu sefer işler geçen seferki kadar güzel gözükmüyor.

Not : Bu sayfadaki linkler vasıtasıyla hangi testlerin başarı ile geçtiği veya toplam ne kadar süre aldığı gibi bilgilere ulaşmak mümkün. Ancak testlerden biri başarısız olduysa, Jasmine varsayılan olarak bize direk bunu getirir.

Test ekibindeki arkadaş, kırmızı ile işaretlediğim kısımdan, fonksiyonun "4" sonucunu beklerken, "a4" sonucunu aldığını görüyor ve inşallah şirket bünyesinde kullanılan bir Bug Tracker yazılımına bu Bug'ı giriyor. Sonrasında yaptığı tüm çalışmaları Source Control sistemine Commit/Check In ediyor.

Şimdi top, yazılım geliştirici junior arkadaşa geçti. Başarılı olması gereken ancak olmayan bir test kodu var ve test koduna dokunmadan bunu başarılı hale getirmesi gerekiyor. Düşünüp taşınıyor ve "src" klasörü içerisindeki "program.js" dosyasının içeriğini aşağıdaki şekilde değiştirip Source Control sistemine Commit ediyor. Konuyu ilgili Bug Tracker yazılımında da "Çözüldü inşallah" konumuna çekiyor.


Şimdi top, tekrar test ekibindeki arkadaşa geçti. Onun şu noktada yapması gereken tek işlem, "SpecRunner.html" sayfasını açmak ve aşağıdaki görüntü ile karşılaşmak olacaktır. Artık girilen Bug'ın durumunu Çözüldü'ye çekebilir.


Pekala, toparlayalım. Elbette burada yazılan testler, bu fonksiyonu tam anlamıyla test etmeye yetmez, daha pek çok test yazılabilir. Ancak amacımız, Jasmine ile test kodunun nasıl yazılacağını öğrenmekti ve sanırım amacımıza ulaştık. Tek bir sınıf/dosyadaki kodu test eden tek bir test sınıfında iki ayrı test fonksiyonu yazarak, her ikisinin de başarılı olduğunu gördük.

İhtiyaca göre, sınıf/modül sayısınca test sınıfı ve bunların içerisine yüzlerce test fonksiyonu yazılabilir. Biz burada sadece "expect" ve "toEqual" fonksiyonlarını kullandık ancak Jasmine bize bundan çok daha fazlasını sunuyor. Ama tek bir makalede yeterince bunalttığımı tahmin ediyor ve bunları sonraki makalelere bırakıyorum.

Makalemizi noktalarken, öğrendiklerimizi özetleyelim.
  • Jasmine ile programdan beklenen fonksiyonaliteye göre uygun test fonksiyonlarını yazarız.
  • Jasmine'in bizim için önerdiği bir dizin yapısı vardır ancak biz bunu istediğimiz gibi değiştirmekte özgürüz.
  • Tavsiye edilen, her bir kod sınıfı için ayrı bir test sınıfının yazılması şeklindedir.
  • Test sonuçlarını tarayıcı üzerinde görmek için Jasmine bize kullanabileceğimiz bir HTML belgesi sunar.
  • Bu HTML belgesinde başarılı testler yeşil, başarısız testler ise kırmızı ile işaretlenir. Sayfa üzerindeki linkler vasıtasıyla test sonuçları hakkında daha fazla bilgi sahibi olabiliriz.


Yorum Gönder

  1. Çok güzel anlatım tarzınız var ve çok bilgilendirici her satırını ince ince okumak gerek fakat bazı kodlar görüntülenmiyor. Sayfayı mac'den chrome ve firefox ile açtım ikisinde de aynı sorun var. (Geçici çözüm: aynı sorunu yaşıyan arkadaşlar page source'u açıp oradan ilgili satırı bulup zor imkanlarda da olsa kodu görebiliyorsunuz.)

    YanıtlaSil
    Yanıtlar
    1. Hmm. Sayfayı Linux ve Windows işletim sistemlerinde görebiliyorum ama Mac üzerinden hiç incelememiştim. İnşallah yakın zamanda bir Mac bulup sayfaları inceleyebilirim. Bilgilendirme için teşekkür ederim.

      Sil
  2. ders ile alakalı asıl kodları görünmüyor

    YanıtlaSil

 
Top