test first

Yazdığınız makaleleri ve üyelerimizin işine yarayacağını düşündüğünüz kodlarınızı gönderebilirsiniz. Bu foruma soru sormayın!
Cevapla
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

test first

Mesaj gönderen sadettinpolat »

teste dayalı yazılım geliştirme (çok alakasız bir isim aslında) yaparken şöyle bir yol izleniyor.

Önce test yazılıyor ardından asıl kod. Başlangıçta biraz kafa karıştıran bir ifade çünkü olmayan bir kodun testi nasıl yazılır? diye bir soru geliyor insanın aklına. YazilimMuhendisligiTurkiye grubundaki arkadaslar saolsun bu soruyu aydinlattilar :)


adımlar şöyle işliyor

1. İşleme başlıyoruz. İlk adımda yeşil ışığımız yanıyor.
2. Testimizi yazıyoruz
3. Testimizi çalıştırıyoruz. Ne test ettiğimiz fonksiyonun adı ne de sanı meydanda olmadığı için compiler syntax hatası veriyor. Işığın rengi burda sarı oluyor.
4. Test edilecek fonksiyonu tanımlıyoruz ama sadece gövdesini amaç undeclareded identifier hatasından kurtulmak :)
5. Testimizi çalıştırıyoruz. Henüz foksiyonumuz görevini doğru bir şekilde yerine getirmediğinden dolayı hata alıyoruz. bu da kırmızı ışık oluyor.
6. Şimdi fonksiyonun gövdesini doldurmaya başlıyoruz.
7. Testi yeniden çalıştırıyoruz. ta ki yeşil ışık yanana kadar...


Bu şekilde devam ettikten bir süre sonra elimizde ürün olarak nitelendirebileciğimiz asıl fonksiyonlarımız oluşmuş oluyor.


bundan sonra sesli düşünüyorum. Sizde bana katılabilirsiniz.

Faktöriyel hesaplayan bir fonksiyon yazmam lazım. Faktöriyeli lise yıllarında görmüştüm ama şimdi çok fazla bir bilgi kalmadı. Zaten çokta önemli değil. Bana lazım olan 3,5 sayının faktöriyeli. bunları döndüren bir fonksiyon yaptığım zaman olay bitmiştir :) tabi önce test kodunu yazmam lazım.

hemen bir proje oluşturuyorum, ardından dunit ile buna bir test projesi ekliyorum hemen ardından bir testuniti oluşturup ilgili uniti aşağıdaki şekilde düzenliyorum.

Kod: Tümünü seç

unit Unit1Tests;

interface

uses
  Unit1,
  TestFrameWork;

type
  TMyTest = class(TTestCase)
  private

  protected

//    procedure SetUp; override;
//    procedure TearDown; override;

  published

    // Test methods
    procedure TestFaktoriyel;

  end;

implementation

{ TMyTest }

procedure TMyTest.TestFaktoriyel;
begin
Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !');
end;

initialization

  TestFramework.RegisterTest('Unit1Tests Suite',
    TMyTest.Suite);

end.
Test projemizi çalıştırıyoruz.

[Error] Unit1Tests.pas(31): Undeclared identifier: 'faktoriyel'

hatası alıyoruz. çünkü faktoriyel diye birşeyimiz henüz yok.
SARI IŞIK

Unit1 e gidip faktoriyel adında bir fonkisyon tanımlıyorum. içinede abuk subuk bişeler yazıyorum.


Kod: Tümünü seç

//unit1.pas

function Faktoriyel(Sayi:Integer):Integer;
begin
        result :=0; //maksat delphi hata vermesin :)
end;
şimdi testimi yeniden çalıştırıyorum.


TestFaktoriyel: ETestFailure at $00486A68 faktöriyel yanlış çalışıyor bilader ! hata mesajını alıyorum. Bu da KIRMIZI IŞIĞIMIZ oluyor. Bunu yeşil yapana kadar işleme devam ediyoruz. Yani fonksiyonu yazmaya başlıyoruz.

Şimdilik bana sadece belirli bazı sayıların faktöriyelleri lazım olduğundan öyle çok genel bir formul aramyorum. yazıyorum makineye istediğim sayıları, hesaplatıyorum faktöriyellerini :) bu sonuçta karşıma çıkan fonksiyon böyle oluyor.

Kod: Tümünü seç

function Faktoriyel(Sayi:Integer):Integer;
begin
  Case Sayi of
    0: Result :=1;
    1: Result :=1;
    2: Result :=2;
    3: Result :=6;
    4: Result :=24;
    5: Result :=120;
    6: Result :=720;
    7: Result :=5040;
    8: Result :=40320;
    9: Result :=362880;
  else
    Result :=0;
  end;
end;
iyi mi ?
değil ama işimi görüyor :)

testimi çalıştırıyorum.... ohhhh ! paşalar gibi yeşil ışığım yandı. gurur duydum kendimle :) artık projeyi gönül rahatlığı ile derleyip gönderebilirim müşteriye....

tabi böyle test olur mu diyorsunuz? haklısınız hemen birkaç değerle daha test ediyoruz.

Kod: Tümünü seç

Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !');
Check(unit1.faktoriyel(5)=120,'faktöriyel yanlış çalışıyor bilader !');
Check(unit1.faktoriyel(9)=362880 ,'faktöriyel yanlış çalışıyor bilader !');
hala yeşil ışık yanıyor...

denemelere devam....

Kod: Tümünü seç

Check(unit1.faktoriyel(10)=3628800 ,'faktöriyel yanlış çalışıyor bilader !');
satırını ekleyince... güümmm ! kırmızı ışık... foksiyon faktoriyel(10) satırının sonucu olarak geriye 0 döndürüyor oysaki 362880 döndürmesi lazım. o zaman diyoruzki bizim yol yanlış sen bu işten vazgeç. mantığı değiştiriyoruz.

Kod: Tümünü seç

function Faktoriyel(Sayi:Integer):Integer;
begin
 if Sayi = 1 then Result := 1
 else Result := Sayi * Faktoriyel(Sayi-1);
end;
olarak değiştiriyorum ve testi yeniden çalıştırıyorum. yeşil ışık yanıyor. test yine içime sinmiyor. bir iki sayıyla daha test etmek istiorum. mesela 0 ile.

Kod: Tümünü seç

Check(unit1.faktoriyel(0)=1,'faktöriyel yanlış çalışıyor bilader !');
satırını ekliyorum ve Stack Overflow hatası alıyorum. Bi yerlerde bi hata var.

Kod: Tümünü seç

 if Sayi = 1 then Result := 1 
satırını

Kod: Tümünü seç

 if Sayi < 1 then Result := 1
şeklinde değiştiriyorum ve test ediyorum. Yeşil ışık.


bir iki test daha yapıp olayı noktalamak istiyorum.

Kod: Tümünü seç

Check(unit1.faktoriyel(15)=1307674368000,'faktöriyel yanlış çalışıyor bilader !');
pat ! bir hata daha. sonuç integer değerlerine sığmıyor. işin ilginç tarafı delphi "sınır aşıldı" diye bir hata vermiyor. sığmayanı atıyor sığdığı kadar sonucu geri dönderiyor. Böyle bir durumda bu hatayı bulmak binlerce saç telinize mal olabilir.


fonksiyonun son şekli

Kod: Tümünü seç

function Faktoriyel(Sayi:Integer):Int64	;
begin
 if Sayi < 1 then Result := 1
 else Result := Sayi * Faktoriyel(Sayi-1);
end;
test ediyorum. Yeşil ışık.

son bir test ekliyorum.

Kod: Tümünü seç

Check(unit1.faktoriyel(19)=121645100408832000,'faktöriyel yanlış çalışıyor bilader !');
çalıştırıyorum. yeşil ışık. Problem yok...

huzurlu bir şekilde save all diyip ide yi kapatıyor ve nargile içmeye gidiyorum...


test kodum ve bu kodlar sayesinde ortaya çıkan asıl kodum.

Kod: Tümünü seç

{ TMyTest }

procedure TMyTest.TestFaktoriyel;
begin
  Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(0)=1,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(5)=120 ,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(9)=362880 ,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(10)=3628800,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(0)=1,'faktöriyel yanlış çalışıyor bilader !');
  Check(unit1.faktoriyel(15)=1307674368000,'faktöriyel yanlış çalışıyor bilader 1!');
  Check(unit1.faktoriyel(19)=121645100408832000,'faktöriyel yanlış çalışıyor bilader 2!');
end;

asıl kod

Kod: Tümünü seç

function Faktoriyel(Sayi:Integer):Int64	;
begin
 if Sayi < 1 then Result := 1
 else Result := Sayi * Faktoriyel(Sayi-1);
end;
kaynak kod için buraya tıklayın
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Kullanıcı avatarı
pro_imaj
Kıdemli Üye
Mesajlar: 1364
Kayıt: 18 Oca 2005 05:45
Konum: Dünyadan

Mesaj gönderen pro_imaj »

Merhaba Sadettin hocam;
Gerçekten güzel ama bir o kadarda karışık bir olay bu inanın kafam karıştı.
Sorun çözme algoritmasına benzer yanisorunlar parçalanarak birleştiriyor. :)

Ben yinede Sorun çözme algoritmasını kullanmayı tercih ederim.

Elinize sağlık güzel bir yaklaşım olmuş hocam.

Kolay gelsin.
Gün gelecek, dilleri, elleri ve ayakları yapmış oldukları bütün kötülükleri tek tek bildirerek aleyhlerinde şahitlik edecektir. [Nur Suresi 24]
_________________
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

aslında tdd (test driven development) baya geniş bir konu. burda ufak bir uygulaması var aslında ama extrem programing denen yazılım geliştirme yönteminin ve diğer bir çok yazılım geliştirme yönteminin en temel taşı.

tdd bize işini çok iyi yapan kodlar vadetmiyor -ki zaten bunu yapamaz- ama elimizdeki kodun mantık hatası içersede içermesede bizim istediğimiz gibi çalıştığını çok hızlı bir şekilde test edebiliyor. bu da varolan kodlarımızı güvenle ve korkmadan geliştirebilmemize olanak sağlıyor.

tdd, xp, unit testing ve dunit ile ilgili bazı linkler

http://www.elvenware.com/charlie/confer ... index.html
http://blogs.slcdug.org/rhordijk/archiv ... 1/251.aspx
http://blogs.slcdug.org/rhordijk/archiv ... 2/221.aspx
http://www.testdriven.com/
http://www.extremeprogramming.org/
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Peki testin doğruluğundan nasıl emin oluyorsun? Her şartta bu test doğru çalışır mı? :)

Yani şunu merak ettim.

Kod: Tümünü seç

Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !'); 
Bu olayı doğru yaptın mı? Testin testi olur mu? :)

Yoksa ben çok çok yanlış mı anladım bunu?
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

coderlord yazdı:Peki testin doğruluğundan nasıl emin oluyorsun?
içgüdüsel :) bu tamamen size kalmış.
ben bu şekilde test etmeyi yeterli buldum. faktoriyel(1)=1
ama bazı insanlar daha değişik yollarla da bunu test edebiliyor. mesela faktoriyel hesaplayan başka bir fonksiyon kullanabiliyor. bu tamamen size kalmış. önemli olan şu: test kodlarınız ne kadar güvenli olursa asıl kodunuz da o kadar güvenli demektir.

testleri yanlış yazmak mümkün müdür? tabiki mümkündür.
coderlord yazdı: Yani şunu merak ettim.

Kod: Tümünü seç

Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !'); 
Bu olayı doğru yaptın mı? Testin testi olur mu? :)
testin testini de yapan uçuklar var. jester, nester denen programlar var. http://www.sf.net te bulmak mümkün.

bu programlar şunu yapıyorlar.

Kod: Tümünü seç

Check(unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !'); 
satırını bi kere çalıştırıyorlar ve sonucu bir yere kaydediyorlar.

ardından ilgili satırın şart bölümüne bir not ekliyorlar.

Kod: Tümünü seç

Check(not unit1.faktoriyel(1)=1,'faktöriyel yanlış çalışıyor bilader !'); 
ve ilgli satırı yeniden çalıştırıyorlar. her iki ifadenin sonucuda eşitse test kodunuzda hata var diye sizi uyarıyorlar....

kısaca yazdığınız kodların doğruluğundan nasıl ki emin olamıyorsunuz yazdığınz test kodlarınında doğruluğundan emin olamazsınız.

biraz karışık oldu ama biraz da benim yetersiz anlatımımdan kaynaklandı galiba... :oops:
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
fduman
Moderator
Mesajlar: 2749
Kayıt: 17 Ara 2004 12:02
Konum: Ankara

Mesaj gönderen fduman »

Eline sağlık harika bir makale oldu.

Son yazınla yanıtımı da aldım. Test function'unun da önemli olduğunu kavradım. Merak ettiğim buydu.

Böyle yazılar bekliyorum senden sadettin.

Mesela bu makaleni bir gerçek yaşam uygulamasında kullansan. Mesela test olayı DB programcılığında kullanılabilir mi? Ben düşündüm de aklıma gelmedi. Neyi test edebiliriz ki?
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

coderlord yazdı:Neyi test edebiliriz ki?
bu soru yerine şöyle sormalıyız aslında

"nasıl test edebiliriz?"

kendi yazdığım kodlar için konuşursak şu ana kadar yazmış olduğum kodların tamamına yakın kısmı için test yazamıyorum. :( çünkü kodlar test edilmeye elverişli bir düzen içerisinde yazılmamış. butonun clik olayına kodları doldurmusumda doldurmusum. bi yapısallık yok, bi duzen yok. bu nedenle testte yazamıyorum. zaten test yazmanın bize katacagi guzel yanlardan biri de bu: duzenli bir kod yazmamızı saglayacak.

aslında kabaca sistem şöyle:
bir yazılımın, birbirinden bağımsız birçok ufak modulden meydana geldigi düşüncesinden yola çıkarsak tdd nin yaptığı işi şöyle açıklayabiliriz.

sistemden (yazılımdan) bir modülü (nesneler, fonksiyonlar, prosedurler) çıkartıp test ortamına sokuyoruz ve doğru çalışıp çalışmadığına bakıyoruz. doğru çalışıyorsa elimizdeki modülü yerine koyup sistemden başka bir modülü alıp test ortamına sokuyoruz ve test ediyoruz. bu böyle modüller bitene kadar devam ediyor.

işin kötü tarafı ise şu: yazılım sonuçta bu modüllerin birleşmesinden meydana gelen bir şey. modüller tek başlarına doğru çalışıyor olabilir ama ya bir arada çalıştıklarında hatalı işlem yapıyorlarsa :?:

eksik kaldığı diğer bir husus ise gui ler test edilemiyor galiba veya zor. tam bilgim yok bu konuda ?


gerçek hayatta veya db de ise mesela bi örnek ver. nasıl test edebileceğimizi burda hep beraber tartışalım çünkü benimde bu konudaki tecrübelerim bi elin parmakları kadar....

bu işi erbabından öğrenmek için charli calvert amcaya kulak vermeklazım :)
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

burda tsqlunit adındaki bir frameworkle sql serverdaki fonksiyonlar test edilmiş...

http://www.codefez.com/Home/tabid/36/ar ... lunit.aspx
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Kullanıcı avatarı
sadettinpolat
Moderator
Mesajlar: 2131
Kayıt: 07 Ara 2003 02:51
Konum: Ankara
İletişim:

Mesaj gönderen sadettinpolat »

tdd (unit test) ile ilgili ufak bir alinti. bana göre testlerin ne oldugu ne olmadığı gayet açık bir şekilde ifade edilmiş burda.
...
...
...
Bu arada ilginc bir durum da var. Unit testlere onem veriliyor, iyi,
hos da, unit test yazilim projesinin basarisi icin gereklidir ama
yeterli degildir. Unit test kod'un dogru calistigina bakar ama
mantigini test etmez. Sanki unit test varsa hersey yolundaymis gibi
bir hava sezdim ilgi konusmada. -http://javaboutique.internet.com/reviews/ruby/- Hersey yolunda degil. Unit test unitlerin dogru calistigini ve degisiklik yapildiginda kod'un
kirilmadigini test eder. O kadar. Onun icin olmasi gerektiginden
daha fazla bir anlam yuklenmemesi lazim. Isleyis yanlis/eksik
algilandiysa, unit test bu durumu test etmez. Dikkat edilmezse
calisan ama is gormeyen bir yazilim paketi elde edilir.

Hayirli aksamlar dilerim.
--
Ender Batur
enderbatur@gmail.com
http://ebatur.fateback.com
"Sevmek, ne zaman vazgececegini bilmektir." dedi, bana.

---
http://sadettinpolat.blogspot.com/
Cevapla