Delphide Assert kullanımı / Sistematik proje testi

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:

Delphide Assert kullanımı / Sistematik proje testi

Mesaj gönderen sadettinpolat »

Anet haber grubunda okudum. güzel bir yazı buraya da göndereyim dedim. konuyla ilgili daha fazla bilgisi olan arkadaşlar varsa onların bilgilerinden de yararlanmak isteriz.


Ahhh test meselesi. Versiyon kontrolle ilgili postunu da okumuştum. O mesele
burada çok kereler konu edilmişti. Aşağı yukarı bu iki postundan ne durumda
olduğunu anlayabiliyorum. Bu test işi burada pek geçmediği için şöyle genel
anlamda birşeyler karalayım dedim. Hem genel bir bilgi olsun hem de belki
işe yarar birşeyler bulursun. Artık Delphi ile pek program yazamıyorum ama
hala delphi gurubumuza bir katkıda bulunabiliriz.



Program yazarken zaman zaman varsayımlar yaparız. Mesela bir değişkenin
değerinin her zaman 0 dan büyük olacağını farzederiz. Bu varsayımlar bizi

if myvar < 0 then raise exception ...... gibi bir test yapmaktan kurtarır.
Ancak böyle bir varsayımda bulunduğumuzu unutmamak için

assert(myvar > 0, 'Dikaaaaaat değişken sıfırdan küçük');

gibi bir kod ilave ederiz. Bu bilhassa birden fazla kişinin çalıştığı
ortamlarda faydalıdır. Bu sayede birisi ilgili kuralı ihlal ederse bundan
haberi olabilir. Nasıl ki kullanıcılarımız için yapmamaları gereken bir
durumda uyarı veriyorsak asserti de programcılar (veya kendimiz) için bir
uyarı olarak düşünebiliriz. Hem programı da gereksiz testlerden kurtarmış
oluruz. Peki assertin kendisi zaten bir test değil mi neden normal bir if
testi yerine assert kullanacağız? Assertler kapatılabilirler. Yani
isterseniz kullanıcı için derlediğiniz versiyonlarda assert satırlarını
derleyicinin ignore etmesini sağlayabilirsiniz. Aslında sağlamalısınız. Eğer
programı assertli derlenmiş halde kullanıcılarımıza gönderirsek zaten
programın düzgün çalışması durumunda her zaman true döndürmesi gereken
testleri de yapıyoruz anlamına gelir. Bu performans kaybına neden olacaktır.
Test için yazılan kodlar test versiyonunda kullanılmalıdır. Eğer
kullanıcılardan assert hataları geliyorsa bu test sisteminde zaaflar var
demektir.

Gelelim asıl konuya. Assert basit işler için çok kullanışlı olsa da
aslında yetersizdir. Çünkü asıl ihtiyacımız yeni eklediğimiz özelliklerin
mantıkta genel bir soruna yol açıp açmadığını anlamaktır. Genelde belirli
bir seviyeden sonra programın kontrolü zorlaşır. Zaten bir test prosedürüne
ihtiyaç duyuyorsak program belli bir aşamaya gelmiş demektir. İki nedenle
kodda değişiklik yapıyoruz. Biri müşteri ihtiyaçlarından kaynaklanıyor biri
de altyapıda değiştirmek istediğimiz meselelerden. Müşteri istekleri
genellikle iyi tasarlanmış programlarda kolay çözülür. Genel olarak OOP
kurallarını ihlal etmeden yazılmış her programda istek kabilinden meseleleri
eklemek kolaydır. Ama ya altyapı konuları? İşte kazık olan kısım burası.
İsteklerle ilgili müdaheleler estetik amelliyata benzese de altyapıyla
ilgili meseleler açık kalp amelliyatına benzer. Hatta bazen hastalık o kadar
çok yayılır ki deyim yerindeyse kalbi, mideyi, kokoreçleri felan çıkarıp
masanın üzerine yaymak gerekebilir. Assert bu işi ne yazık ki kurtarmaz.
Bize yaptığımız müdaheleden sonra hasta tüm eski işlevlerini yerine
getirebiliyor mu bunu denetleyecek bir sistem lazım. "Acaba bir yeri bozdum
mu?" cidden kötü bir soru.

İşte birim testleri (unit tests) bu noktada iyi bir yardımcı olacaktır.
Buradaki anafikir programımızdaki sınıflarımızı (veya genel olarak bazı
işlevleri) küçük bir simülasyon tarzında sınamaktır. Yine OOP kurallarına
uyulmuş olması bu tür testlerin hazırlanmasında iyi bir ortam olacaktır.
Yani event-driven (evente tıkla kodu yaz) şeklindeki programcılık bize ayak
bağı olabilir.

Bunun için Delphide kullanılmak üzere tasarlanmış DUnit isimli program
kullanılır. Programa yeni bir işlev eklediğinizde DUnit'e de bu işlevi
denetleyecek bir test yazar ve eklersiniz. DUnitte her test bir renkli kutu
ile ifade edilir. Kırmızı kutular patlayan testleri, yeşil kutular ise
geçerli testleri ifade eder. Program yazılırken bir taraftan testleri de
yazarsınız. Yani programda yazdığınız kodları kullanan bir başka program da
bu esnada yazılır. Sonra zamanı geldiğinde bu testler tümüyle işletilir ve
patlayan kısımlar düzeltilerek hatalar ayıklanır. Örneğin ortalama vade
hesaplayan bir fonksiyonumuz olsun.

calcOrtalamaVade(Tarih arrayi; Tutar arrayi) :Gün sayısı;

gibi. Biz bu fonksiyona örnek bir bir değer kümesi gönderen ve önceden
hesapladığımız vadeyi bulup bulamadığımızı test eden ayrı bir fonksiyon daha
yazarak testlerimiz arasına ekliyoruz. Sonra bu testleri her
çalıştırdığımızda bu ortalamaVade testi de çalışıyor. Böylelikle biz böyle
bir işlevi unutsak dahi aylar sonra buradaki kodu kıracak bir kod yazarsak
ortalama vadenin doğru hesaplanıp hesaplanmadığı testler esnasında ortaya
çıkacaktır. Gavurlar bu tarz program yazmacaya "Test Driven Development"
derler.

Bir de şunu düşünelim Yukarıdaki vade hesabı gibi bir fonksiyonu yazdık ve
bir müşterimiz 29 şubat vadeli bir çeki girdiğinde ortalama vadenin bir gün
eksik hesaplandığından bahsetti. Ne yazıkki artık paldır küldür koda dalıp
"lan bu 29 şubatın ta bilmemnesini" nidalarıyla bug temizlemek yok. Hemen
gidip paşa paşa önce 29 şubat tarihinde hatalı hesaplanan durumu ortaya
çıkaran bir test yazıyoruz. Testi çalıştırdığımızda kırmızı kutu bize hatalı
durumu gösteriyor. Sonra tüm kırmızı kutucuklar yeşile dönene kadar bu tarih
sorununu çözecek kodu düzeltiyoruz. Programa girip çek felan işleyerek
yaptığımız düzeltmeyi test etmek hem uzun sürer ve sıkıcıdır hem de bu
düzeltmeyi yaparken başka bir tarafı bozduysak bu gözden kaçar.

XP (Extreme Programming) son günlerin en moda yazılım metodojilerinden
biridir. Birim testleri XP'nin en can alıcı noktalarından biridir. Hatta XP
guruları der ki programa birşey eklemeden önce testini yazın. Mesela mail
atacak bir sınıf yazacaksınız.

TMailSender = class
procedure Sendmail(AMessage,AAddress:String);
Function CheckMail(AAddress):AMessage;
end;

Şimdi ctrl +c ile boş metodları oluşturuyoruz ve birşey implement etmeden
önce testi yazacağız. Bu sınıf uMail.pas unitinde ise uMail_Test.pas unitine
de aşağıdaki kodu ekleyebiliriz.

// MailSender testi
const teststr = 'DENEME 1 2 3';
var s:String;
MS := TMailSender.Create;
MS.SendMail(teststr, 'adresim@domainim.com');
s :=MS.CheckMail('adresim@domainim.com');
MS.free;
assert(s=teststr);
//

ve bu testi bir satır kod daha yazarak DUnit'e register ediyoruz. Test
programını çalıştırdığımızda DUnit çalışacak ve ilgili testi kırmızı ile
gösterecektir. Artık yeşil görene kadar sınıfı implement edeceğiz. İşimiz
bittiğinde hem denemelerimizi yapacağımız güzel bir ortamımız olacak hem de
birgün bozulursa direk haberdar olacağımız şekilde kodu garantiye almış
olacağız. Gerçekten de bu şekilde çalışıldığında belkide sadece kullanıcı
arabirimini test etmek için programı çalıştıracaksınız :)))

Eğer programımızın işlevlerini DUnit ile test edebiliyorsak altyapıyı veya
tasarımı yenilerken (buna da gavurlar Refactoring diyor) programın doğru
çalıştığından tam olarak emin olacağımız ortamı da oluşturmış oluruz. Tabii
ben bu mail meselesini örnek olarak verdim. Test bir sınıfla alakalı
olabileceği gibi bir işlev bütününün testi de olabilir.

Eğer yeni bir projede birim testlerini de yazmaya karar verirsek iş nispeten
kolay. Ancak mevcut bir projeye birim testleri yazmaya kalkarsak muhtemelen
çakılırız. Çünkü kodumuz büyük ihtimalle *test edilebilir* durumda
olmayacaktır. Dolayısıyla neyin nasıl test edileceği konusu havada kalır.
Muhtemelen mail gönderecek bir sınıf yazmamış ve değişik mail işlevlerini
bir formun buton eventlerine yaptırıyoruzdur. İşte en başta dediğim gibi OOP
kurallarına uymama sorunu budur. Projeyi test edilebilir hale getirmek de
apayrı bir konudur. Bunun da gavurcası Retrofitting' dir. Ama zorluğuna
rağmen bence Test Driven Development işinin en güzel yanı da budur. Bu
çalışma programcıyı test edilebilir kod yazmaya mecbur eder. Test
edebildiğimiz kod iyi koddur.

Genelde ilk başlarda biraz karmaşık gibi görünse de alışkanlıklarımızı bir
an bir kenara bırakıp farklı bir tarz yakalayabilirsek bu çalışma şekli çok
faydalıdır. Belki normalden biraz fazla kod yazılması gerekecektir ancak
uzun dönemdeki kazanç büyüktür. Hadi abartalım ideal bir sistemde programın
bir bölümünü silip gönül rahatlığıyla yeniden kodlayabilirsiniz. Özellikle
uzun süre yaşaması gereken bir proje üzerinde çalışıyorsak ve test konusunda
milyarlarca lira dökecek bir dayı firmamız da yoksa bu basit iş hayati önem
taşır.

Uzun yazdım inşallah bir okuyan bulunur:)) Her gün yeni şeyler öğrenmek ve
uygulamak durumundayız. Bu programcının kaderi. Googılda Test Driven
Development yazarsak karşımıza birçok kaynak çıkacaktır. Ayrıca DUnit
opensource bir projedir ve tam adresini hatırlayamayacağım ama sourceforge
de aratılabilir.

Hadi kolay gelsin.

Emre Eren

"Ahmet Aksoy" <ahmetax@axtelsoft.com> wrote in message
news:40ee68b4_6@news.anet.net.tr...
> Delphi'de test için assert kullanan var mı?
> Büyük projelerde yapılan revizyonlar, bazan sistemin başka yerlerini
> bozuyor. Bu durumu farketmek te zaman alıyor. Tüm projeyi her revizyonda
> sil baştan teste sokmak ta pe mümkün olmuyor.
> Bu işi delphi de hayata geçirebilmek için ne yapılabilir?
> WinXP-Pro/Delphi 7 Pro kullanıyorum.
Cevapla