Yazılım Mühendisliği

Ekim 10, 2008

Test Driven Development(TDD)-1

Filed under: TDD — Yahya KOÇ @ 7:42 pm
Tags: , ,

Klasik yazılım anlayışında “kodu test etmek” denilince bitmiş kodu çalıştırıp -arayüz yardımıyla- kayıt ekleme-silme-güncelleme işlemlerini test etmek anlıyorduk.Hata bulduğumuzda patlayan yere bir yama..Tekrar test..Tekrar yama..Bir de arada akış içerisinde değişiklik istekleri…En sonunda elimizde bir yamalı bohçayla ortada kalırdık.
“Test First Design” tasarım mantığıyla, çalışacak kodu yazmadan önce, o kodu çalıştırmayacak kodları yazıyoruz. “Yazılacak” kodun çalışmasına engel olacak durumları kodlayarak hem testlerimizi oluşturuyoruz hem de çalışacak kodumuzun dizaynını şekillendirmeye başlıyoruz. (Çevik yöntemler 10.madde)

“Test yazmak için zamanım yok” diyenlere şöyle sesleniyoruz:

  • Test yazılmayan kod, geliştiricisine daha çok stres getirir.(Hata nerede? Ara ki bulasın!!)
  • Daha çok stres daha çok hataya yol açar.(Aceleyle yapılan hata düzeltmeler yeni hatalar meydana getirir.)
  • Yeni hatalar daha çok stres getirir.

Bu sonsuz döngü, değil test yazım işlemine ayırmadığınız zamanı neredeyse tüm mesainizi yer,bitirir.

Testleri genel olarak iki ana başlık altında inceleyebiliriz:Unit test ve Acceptance Test.Biz bu yazımızda Unit Test ile ilgileneceğiz.
UnitTest(Birim Test)
Birim test adından da anlaşılabileceği gibi yazılan-aslında yazılacak- kodun en küçük birimlerinden başlayarak oluşturulan testlere verilen addır.En küçük birimden başlayıp adım adım testleri yazarak, çalışacak kodumuzu da adım adım oluşturmuş oluyoruz.Bu işlemi, çok sık aralıklarla atılan düğümlere benzetiyorum.Düğümleriniz ne kadar sık ve sağlamsa ileride o düğümlerin çözülme ihtimali o kadar azdır.O düğümleri atarken harcadığınız -israf gibi görünen- fazla mesai, sizi ileride karşılacağınız hataları düzeltmek için yapmak zorunda kalacağınız “büyük zaman israf”ından kurtaracaktır.
Birim testleri yazarken şu adımlar izlenir:

  • Tek satır kod yazmadan kodun testini yaz.
  • Testi çalıştır ve testin geçilemediğini gör.
  • Testi geçecek en basit kodu yaz.
  • Kodu düzenle (Refactoring)
  • Tekrar başa dön.

Şimdi basit bir Banka hesabı uygulaması yapalım.Birim testler için Nunit kullanacağız.
TDD olmaksızın ilk başta zihnimizde Banka nesnesi,Hesap nesnesi,Mudi,Para gibi nesneler ve ilişkiler canlanırdı.Banka nesnesinden yazmaya başlardık.Hatta “şöyle bir arayüz olsun, bu nesne şu sınıftan türesin,şöyle bir tasarım deseni olsun” şeklinde planlar yapmaya başlardık.TDD ile, bu tür planlamalardan vazgeçip(Test First Design) sistemin en basit ve en uç noktasından başlıyoruz:”Para”…Başka birşey planlayıp hesaplamamıza gerek yok.
İlk testlerimize başlayalım.

  • YTL adında bir paramız olsun.Miktarını set edelim.Miktar alanı düzgün set edilmiş mi?
  • Dolar adında bir paramız olsun.Miktarını set edelim.Miktar alanı düzgün set edilmiş mi?

    [Test]
        public void YTL_YapiciMetodIleDuzgunOlusturulmus_Mu()
        {
            YTL ytl = new YTL(8);
            Assert.AreEqual(ytl.Miktar, 8);
        }

Kodu derleyemiyoruz çünkü ortada YTL adında bir sınıf yok.Resharper bu sınıfı bizim için oluşturuyor.
 public  class YTL
    {
    }

Kodu tekrar derlemeye çalıştığımızda “Miktar” alanına takılıyoruz.Onu da Resharper bizim için oluşturuyor.Tekrar derlediğimizde YTL(8) kısmına takılıyoruz.Zira böyle bir yapıcı yok.Resharper ile bu metodu da oluşturuyoruz.
 public class YTL
    {
        private readonly int miktar;
        public int Miktar
        {
            get { return miktar; }
        }
        public YTL(int _miktar)
        {

        }
    }

Artık kodumuzu derleyebiliyoruz.Test aşamasına geçebildik nihayet…İlk testimizi çalıştırdığımızda şöyle bir sonuç alıyoruz.

Yukarıda görülen hata mesajından anlaşılabileceği gibi(AssertionException:Expected 0 But was 8 ) test sonucunda Miktar değerinin 8 olmasını bekliyorduk.Fakat sıfır geldi.Öyleyse yapıcı metodumuzda gelen parametreyi Miktar alanına set etmemişiz demektir.

 public class YTL
    {
        private readonly int miktar;
        public int Miktar
        {
            get { return miktar; }
        }
        public YTL(int _miktar)
        {
            miktar = _miktar;
        }
    }

Testimizi tekrar çalıştırdığımızda Yeşil çubuğu görebileceğiz.
Aynı işlemleri Dolar sınıfı için yapıyoruz.Yazının uzamaması için o kısmı buraya yazmıyorum.

Yeni testler yazalım.

  • Aynı miktarda iki parayı karşılaştırdığımızda Equals metodu true dönüyor mu?
  • Farklı miktarda iki parayı karşılaştırdığımızda Equals metodu false dönüyor mu?

        [Test]
        public void YTL_Farkli_Miktarlar_Equals_Return_false()
        {
            YTL ytl = new YTL(8);
            YTL yeniYtl=new YTL(12);
            Assert.AreEqual(false,ytl.AyniMi(yeniYtl));
        }
        [Test]
        public void YTL_Ayni_Miktarlar_Equals_Return_true()
        {
            YTL ytl = new YTL(8);
            YTL yeniYtl = new YTL(8);
            Assert.AreEqual(true, ytl.AyniMi(yeniYtl));
        }

Resharper,YTL sınıfının AyniMi adında bir metod içermediğini görüp bizi uyarıyor.Biz de sıfın içinde AyniMi adında bir metod yazıyoruz.
  public bool AyniMi(YTL yeniYtl)
        {
            return Miktar == yeniYtl.Miktar;
        }

Bütün testlerimizi tekrar çalıştırdığımızda baştan aşağı yeşil tikleri görebiliyoruz.
TDD adımları içerisinde “kodu geçebilecek en basit kodu yaz” kuralını şu şekilde uygulayabiliriz.
  public bool AyniMi(YTL yeniYtl)
        {
            return true;
        }

Bu durumda YTL_Ayni_Miktarlar_Equals_Return_true testimiz başarılı olacak ama YTL_Farkli_Miktarlar_Equals_Return_false adlı testimiz başarısız olacaktır.Bu durumda AyniMi metodu içerisinde birşeyler değiştirmemiz gerektiğini anlıyoruz.Dikkat ettiyseniz ben bu adımı atlıyorum çünkü test adımlarınızın sıklığına siz karar vereceksiniz.Eğer “bunu da test etmeme gerek yok,metodun içinde iki testi de geçecek kodu yazarım” diyorsanız yani kendinize güveniyorsanız mesele yok..Ama burda kararı tutturmak lazım yani “iki testi de geçecek kod yazarım” derken bütün testleri de geçecek kod yazmaya kalkabilirsiniz.Bu durumda da TDD’nin temel mantığını tamamen ezmiş olursunuz.

Bir noktaya daha dikkat çekmek istiyorum.Test metodlarına verdiğimiz isimler, tam olarak neyi test ettiğimizi açıkca belirtmesi lazım:”YTL_Farkli_Miktarlar_Equals_Return_false” gibi…
Bir şey daha dikkatinizi çekmiş olabilir.Testler içinde sabit rakamlar kullanıyoruz.Refactoring mantığı içerisinde üzerinde önemle durulan “Replace Magic Number with Symbolic Constant” temel prensibini çiğnemiş oluyoruz.Test metodları için mühim olan asgari kod yazmak olduğu için bu prensibi es geçebiliyoruz.
Bir sonraki yazımızda bu örnek üzerinde yeni testler yazmaya devam edeceğiz.

Yorum yapın »

Henüz yorum yapılmamış.

Bu yazıya yapılan yorumlar için RSS beslemeleri. URI'nin geri izlemesini yap.

Yorum yapın

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Değiştir )

Twitter picture

You are commenting using your Twitter account. Log Out / Değiştir )

Facebook photo

You are commenting using your Facebook account. Log Out / Değiştir )

Connecting to %s

Theme: Rubric. WordPress.com'dan blog alın.

Follow

Get every new post delivered to your Inbox.