Birim Test Nedir? Niçin Yapılır? Nasıl Yapılır?

Monday, 03 Mar 2014 yorum yok

Yıl olmuş 2014 hala birim test makalesi mi yazıyorsun diye düşünüyor olabilirsiniz. Ancak, birim testi uzun zamandır kullanılan bir yöntem olmasına rağmen tam olarak ne işe yaradığı, neden yapıldığı ve nasıl yapılması gerektiği konusunda açıklayıcı bir Türkçe yazı bulmak malesef zor. Bu yüzden, yazılım mühendisi adaylarına ve kariyerine yeni başlayan arkadaşlara faydalı olabilmek adına bu yazıyı yazmak uygun olur diye düşündüm.

Birim Testi Nedir?

Birim testi adından anlaşıldığı üzere yazılım birimlerinin test edilmesidir. Burada yazılım birimi dediğimiz şey ise test edilebilen en küçük yazılım bileşenidir. Nesneye yönelik programlama yaklaşımını ele alacak olursak, yazılım birimleri sınıflardır diyebiliriz. Yapılan şey basit olarak sınıf davranışlarının (metodlar) belirli girdiler sağlandığı zaman doğru bir şekilde çalışıp, istediğimiz sonucu üretip üretmediğini kontrol etmektir. Bu şekilde yazılımın küçük birimleri test edildiği zaman, bütünü oluşturan parçaların en azından kendi içlerinde çalıştığından emin olmuş oluruz. Buraya kadar söylediklerimiz birim testinin genel tanımıdır, ama yazılım geliştiren kişiler olarak asıl anlamamız gereken şey birim testini niçin yaptığımızdır.

Birim Test Niçin Yapılır?

Bu soruyu eminim ki birçok yazılımcı kendi kendine sormuştur. Bir kısmımız tam olarak neye hizmet ettiğini anlamasak da, faydalı olduğunu düşündüğümüz için ve kendimizi daha güvende hissetmek adına birim test yazarız. Bazılarımız ise birim test yazmanın faydalı olduğunu bilmemize rağmen çeşitli bahaneler üreterek birim test yazmaktan kaçarız. Bunun arkasındaki asıl sebep ise birim testlerin ve test odaklı yazılım geliştirme tekniğinin (test-driven development) asıl amacını kavrayamamış olmamızdır. Her şeyden önce şunu söylemek gerekir: Birim testleri yazılımları test etmek için yazılmaz. İsmi “birim test” olan bir yöntem için “asıl amacı yazılımları test etmek değildir” demek ilk başta çok mantıklı gelmeyebilir ama yazıyı okudukça bana hak vereceğinizi düşünüyorum.

Birim testler hata bulmak için değildir

Bir yazılım sistemindeki hataları (bug) bulmak birim testler ile mümkün değildir. Çünkü birim testlerin yaptığı iş yazılımın en küçük parçalarını kendi içerisinde test etmektir. Peki bu küçük parçaların kendi içlerinde çalışıyor olması, yazılımın gerçek kullanıcılar tarafından kullanılmaya başladığı zaman bir bütün olarak çalışacağını gösterir mi? Kesinlikle hayır. Bir yazılım sistemi, onu oluşturan parçaların toplamından çok daha fazlasıdır. Dolayısıyla bu bütünü test etmek için farklı yöntemler kullanmak gerekir. İşlevsel test (functional testing), bütünleştirme testi (integration testing) bunlara örnek verilebilir ancak konumuz birim test olduğu için bunlara değinmeyeceğim.

Hataları bulamıyorsa birim testler ne işe yarıyor?

Birim test yazmanın sağladığı gerçek fayda, bizi kaliteli kod yazmaya teşvik etmesidir. Peki bu nasıl olur? Öncelikle şunu söylemek gerekir ki, birim test yazmanın birinci kuralı test etmekte olduğumuz sınıfı, bağımlı olduğu diğer bütün bileşenlerden izole etmektir. Örnek verecek olursak, test ettiğiniz sınıfın bir Google servisine bağlanarak veri çektiğini düşünün. Ancak birim test esnasında bu sınıfın Google servisine bağlanıp veri çekmesini istemeyiz. Çünkü birim testin amacı yazılımın Google servisleriyle çalışabildiğini kanıtlamak değildir. Birim test yazarken, bağlantılı olduğumuz diğer bütün parçaların sorunsuz biçimde çalıştığını varsayarak yazarız, çünkü odaklandığımız şey sınıfın kendisidir, bağımlı olduğu diğer bileşenler değil. Bu varsayımı yapabilmek için de, mocking dediğimiz tekniği kullanarak test esnasında gerçek Google servisine bağlanmak yerine bizim yarattığımız sahte bir servise (mock object) bağlanıp sınıfın ihtiyacı olan veriyi döndürürüz.  Bu şekilde test ettiğimiz sınıf dışarıda bir servise bağlanmadan ihtiyacı olan veriyi alır ve işletimini tamamlar.

Şimdi test etmekte olduğumuz bu sınıfın dışarıdaki Google servisiyle sıkı sıkıya bağlı (tightly coupled) olduğunu düşünün. Sınıf Google servisiyle ilgili bütün bilgileri içinde barındırıyor ve bağlantıyı yaratıp kullanıyor, veri alışverişini yapıyor. Biz bu sınıfa gerçek Google servisine değil de bizim belirlediğimiz sahte servise (mock object) bağlanmasını nasıl söyleyeceğiz? Bu şekilde birbirine sıkıca bağlanmış yazılım bileşenlerini birbirlerinden bağımsız bir şekilde test etmek mümkün değildir. Ancak bu bileşenler gevşek bağlı (loosely coupled) olsaydı, biz sınıfımıza test esnasında sahte servisi, gerçek işletim esnasında ise Google servisini kullanmasını söyleyebilirdik. Bu şekilde yazılım bileşenlerini birbirlerine gevşek bir biçimde bağlamak Dependency Injection tekniğiyle mümkündür ve gevşek bağlı sistemler çok daha kolay bakım yapılabilen, test edilebilen ve eklemeler yapması çok daha kolay olan sistemlerdir.

Test odaklı yazılım geliştirme yapıyorsak (test-driven development), birim testleri sınıfın kendisinden önce yazmamız gerektiği için bu tarz tasarım detaylarını henüz işin başındayken doğru bir şekilde belirlemiş oluruz. Doğru biçimde birim test yazmak, yazılım bileşenlerini birbirlerine sıkı sıkıya bağlamamızı engelleyerek daha tasarım aşamasındayken daha kaliteli bir yazılım çıkarmamıza yardımcı olur. Özet olarak şunu söylemekte fayda var, bütün bileşenleri birbirinden bağımsız olarak test edilebilen yazılımlar, bakımı nispeten daha kolay olan ve kaliteli yazılımlardır. İşe birim testleri yazarak başlamak da bunu başarmamıza yardımcı olur.

Birim test yazmak kodda iyileştirme yapmayı (refactoring) kolaylaştırır

Birim test yazmanın bir diğer büyük faydası da kodda iyileştirme yaparken (refactoring) ortaya çıkar. Hiçbir kod mükemmel değildir ve iyileştirme her zaman bir ihtiyaçtır. Ancak birçok yazılımcı çalışan sistemi bozmaktan korktuğu için iyileştirme yapmaz. Ancak kapsamlı birim testleriniz varsa, değişiklik yaptığınız sınıfın hala çalışıp çalışmadığını anlamak için birim testlerinizi kullanabilirsiniz. Daha önce birim testlerin hataları bulmak için kullanılmadığını söylemiş olsak da iyileştirme esnasında üzerinde çalıştığımız sınıfı bozup bozmadığımızı anlamak mümkün olabilir. Dolayısıyla birim test yazmak sadece kodu yazarken kaliteli yazmaya teşvik etmekle kalmaz, aynı zamanda ileride kodu iyileştirmemize de yardımcı olur.

Doğru birim test nasıl yazılır?

Birim testin nasıl yazılması gerektiği de çok önemlidir. Doğru yazılmayan birim testler bize hiçbir şey kazandırmayacağı gibi en ufak değişiklikte hatalar vermeye başlayıp başımızı ağrıtırlar. Üstüne bir de testlere bakım yapmakla uğraşmak zorunda kalacağımız için de fayda sağlamanın aksine zararlı olabilirler. O yüzden birim test yazarken aşağıdaki noktalara dikkat etmekte fayda var:

  • Tek bir şeye odaklanınHer testin tek bir şeyi test ettiğinden emin olun. Çok gerekli değilse aynı test içerisine birden fazla assert ifadesi koymayın.
  • Bağımlılıkları (dependency) değil, tek bir sınıfı test edin: Yazıda daha önce de değindiğimiz gibi, bir sınıfı test ederken o sınıfı bağımlı olduğu diğer yazılım bileşenlerinden izole edin, aksi taktirde yazdığınız test birim test değildir.
  • Yazdığınız testler birbirini etkilemesin: Yazdığınız her test birbirinden bağımsız bir şekilde tek başına sorunsuz çalışabilmelidir. Eğer yazdığınız bir birim test başka bir birim testin üreteceği veriye bağımlıysa yanlış yapıyorsunuz demektir.
  • Testlerinizi doğru isimlendirin: Test sayısı arttıkça isimlendirmenin önemi de artar. Kafa karıştırıcı test isimleri kullanmak ileride problemlere yol açar. Açıklayıcı olması için test isimlerini uzun tutmanız gerekiyorsa öyle yapın, uzun isimler yanlış isimlerden daha faydalıdır.
  • Test koduna ikinci sınıf kod muamelesi yapmayın: Testler de yazılımın bir parçasıdır. Dolayısıyla normal program kodunu yazarken ne kadar özen gösteriyorsanız test kodlarına da aynı özeni gösterin, kod tekrarlarından kaçının, okunabilir test kodu yazın.

Bir Yazılım Mühendisinin Hayatı – Bölüm 2

Thursday, 21 Mar 2013 1 yorum

İkinci bölümle devam ediyoruz. Birinci bölüm için buraya tıklayın.

Üzerinde saatlerce çalıştığımız bir scripti ilk defa çalıştırmayı denediğimiz zaman:


Devamını Oku…

Bir Yazılım Mühendisinin Hayatı – Bölüm 1

Thursday, 21 Mar 2013 yorum yok

Yazılım mühendislerinin hayatına bir de böyle bakın.. Bu tarz şeyler yaşamıyorsanız gerçekten bir yazılım mühendisi olup olmadığınızı sorgulayın derim :)

Google’da arama yapmadan bir problemi çözdüğümüz zaman:


Devamını Oku…

Redgate SQL Search Plugin

Wednesday, 09 Jan 2013 yorum yok

SQL Server Management Studio 2008 kullanarak veritabanınızdaki bütün tablolar veya saklı yordamlar (stored procedure) içerisinde bir metin aramanız gerektiği zaman yapamadığınızı anlamak uzun sürmüyor. Benim de bugün bütün stored procedureları taramam gerektiğinde üçüncü parti yazılımlara yöneldim Redgate firmasının geliştirdiği SQL Search Pluginini buldum. Plugin SQL Server Management Studio içerisine entegre oluyor ve veritabanınızdaki bütün objeleri arayıp metin bulmayı çok kolaylaştırıyor. Oldukça başarılı olan bu eklenti aynı zamanda bedava. Mutlaka deneyin..

http://www.red-gate.com/products/sql-development/sql-search/

C# – Using Anahtar Kelimesi ve Kullanımı

Thursday, 03 Jan 2013 7 yorum

C# dilinde “using” anahtar kelimesi iki farklı şekilde kullanılmaktadır. Bunlardan birincisi isim uzaylarını (namespace) koda dahil etmek veya isim uzayları ve türlere başka isimler vermek için kullandığımız using bildirimi, ikincisi ise IDisposable arayüzünü gerçekleştiren nesnelerin doğru bir biçimde ele alınmasını sağlayan using ifadesi. Bu kullanımların her ikisini de örneklerle açıklamaya çalışacağım.
Devamını Oku…

Java Servisinin Kendi Kendine Durması Sorunsalı

Thursday, 03 Jan 2013 2 yorum

Çalıştığım şirkette eski de olsa Glassfish 2.1.1 sunucusu üzerinde barındırdığımız bir uygulamamız var. Bütün sistemi daha yeni ve hızlı bir ortama taşımamız gerektiğinde Glassfish uygulama sunucusu yeni donanımlar üzerine yüklendi ve gerekli ayarlamaları yapıldı. Ancak test aşamasında farkettik ki Glassfish sunucusunun yüklü olduğu makinede kullanıcı oturumunu kapattığı anda uygulama yanıt vermeyi kesiyor. Biraz araştırma yapınca farkettik ki kullanıcı makinede oturum kapattığı anda java.exe servisi çalışmayı durduruyor.

Google sağolsun çözümü bulmak çok uzun sürmedi. Meğerse kullanıcı oturum kapattığı anda JVM işletim sisteminden gelen bir sinyalle kendini durduruyormus. Bu davranışı devre dışı bırakmak için JVM parametrelerini biraz kurcalamak gerekti. JVM’yi -Xrs parametresiyle çalıştırdıgımız zaman kullanıcı oturum kapatsa bile JVM arka planda çalışmaya devam edecektir. Bizim sorunumuz Glassfish sunucusu ile olduğu için domain.xml dosyasına -Xrs parametresini de ekleyerek sorunu çözdük.

Ancak dikkat edilmesi gereken bir nokta var. -X ile başlayan JVM parametreleri standart değil yani her JVM gerçekleştiriminde yer almayabilir veya olsa bile aynı şekilde davranmayabilir. Komut satırında java -X komutunu girerseniz sizin JVM’nizin hangi parametreleri desteklediğini görebilirsiniz.

Strateji Tasarım Deseni

Sunday, 15 Apr 2012 8 yorum

Uzun zamandır yazmak istediğim konulardan birisi de tasarım desenleri. Strateji deseni çok sık kullanılan ve çok yararlı olduğunu düşündüğüm bir tasarım deseni olduğu için bununla başlamak istedim. Bu desenin kitaplardaki tanımını verip kafa karıştırmaktansa bir örnekle başlamak istiyorum. Bir şirketimiz olduğunu ve bu şirkette çalışan teknisyen, mühendis ve yönetici türünde elemanlarımız olduğunu varsayalım. Her bir eleman türü için de ayrı ayrı maaş hesaplama algoritmalarımız olsun. Bu durumu koda döktüğümüzde aşağıdaki gibi bir sonuç karşımıza çıkabilir.
Devamını Oku…

C# Pratikleri Bölüm 1 – ? ve ?? Operatörleri

Sunday, 26 Feb 2012 yorum yok

Her ne kadar Java dünyasından gelmiş birisi olsam da şartlar beni .NET ile uygulama geliştirmeye itti diyebilirim. Bu konularda derinlemesine bilgi sahibi değilim, ancak C# ile uygulama geliştirirken karşılaştığım ve öğrenip kullandığım, küçük ama faydalı olabilecek kodlama pratiklerini paylaşmak iyi olur diye düşündüm. Bu ilk yazıda ? ve ?? operatörleri üzerinde durmak istiyorum.
Devamını Oku…

Categories: C# Tags: ,

Git – WinMerge ile diff Kullanımı

Saturday, 28 Jan 2012 yorum yok

Versiyon kontrol sistemi olarak Git aracını kullananlar sanıyorum ki diff komutunu kullanarak dosyaları sıklıkla karşılaştırıyorlardır. Git Bash kullanarak çalıştırılan bu komutun çıktısı da konsol ekranında gösterildiği için, çok sağlıklı bir karşılaştırma yapmak mümkün olmayabiliyor. Özellikle dosyalar arasındaki farklılıklar arttıkça bunları takip etmek çok zorlaşıyor. Bir dosya karşılaştırma aracı olan WinMerge programını Git ile entegre ederek diff komutunun çıktısını görsel olarak çok daha gelişmiş bir biçimde görebiliriz.

Bunu yapmak için öncelikle http://winmerge.org/ adresine giderek WinMerge programını indirip kuralım. Yalnız programı kurarken “Program Files” klasörüne değil de direk “C” dizininin altına kurmakta fayda var çünkü “Program Files” klasörünün ismi boşluk içerdiği için Git ile entegrasyonda bazen problemler olabiliyor. İkinci adım olarak boş bir metin dosyası yaratıp içerisine aşağıdaki satırları girelim (WinMerge programını “C” dizininin altına kurduğumuzu varsayıyorum):

#!/bin/sh
# diff is called by git with 7 parameters:
#  path old-file old-hex old-mode new-file new-hex new-mode
"C:/WinMerge/WinMergeU.exe" "$2" "$5" | cat

Bu dosyayı git-diff-wrapper.sh adıyla kaydedelim. Ancak dosyanın uzantısının .txt olarak kalmadığına dikkat etmemiz lazım. Bu dosyayı da C dizininin altında GitScripts isimli bir klasör oluşturup onun içine atalım. Daha sonra Git Bash içerisinde aşağıdaki komutu çalıştıralım:

git config --global diff.external C:/GitScripts/git-diff-wrapper.sh

Buna alternatif olarak aşağıdaki satırları “C:/Users/(KullanıcıAdınız)” dizini altındaki .gitconfig dosyasına ekleyebilirsiniz. Yukarıdaki komut da zaten .gitconfig dosyasına aşağıdaki satırları eklemektedir.


external = C:/GitScripts/git-diff-wrapper.sh

Bu işlemden sonra Git Bash içerisinde bir diff komutu çalıştırdığımız zaman WinMerge otomatik olarak açılacak ve çok kolay bir biçimde karşılaştırma yapmanızı sağlayacaktır.

Categories: Git Tags: ,

Java’da Gizli (Implicit) ve Açık (Explicit) Parametreler

Tuesday, 18 Oct 2011 yorum yok

Programlama dillerinde bir işlev, fonksiyon veya yöntem (metod) çağırırken veri geçişi için parametreler kullanılır. Java dilinde de aynı şey geçerlidir. Aşağıdaki gibi bir yöntemimiz olduğunu düşünürsek;

public void maasArtir(double oran) {
	maas += maas * oran/100;
}

yukarıdaki yöntem parametre olarak double türünde bir değer almakta ve nesne değişkeni olan “maaşı” artırmaktadır. Parametre olan “oran” değişkeni yöntemin imzasında açıkça tanımlandığı için açık (explicit) parametredir. Buraya kadar ilginç birşey yok, bildiğimiz şeyler. Şimdi bu yöntemin Personel isimli bir sınıf içerisinde tanımlı olduğunu düşünelim ve Personel sınıfından yarattığımız personel1 adında bir nesnemiz olsun.

Personel personel1 = new Personel();

Daha sonra personel1 nesnesi üzerinden maasArtir yöntemini çağıralım.

personel1.maasArtir(20);

Bu koda göre personel1 nesnesine ait olan “maas” değişkeni %20 oranında artacaktır. “oran” parametre değişkeni açık parametre ise yazının başlığında belirttiğimiz gizli parametre nerededir? Java dilinde yöntem çağırırken kullandığımız nesne referansı da yönteme parametre olarak gönderilmektedir. Yani nesne referansımız olan personel1, maasArtir yöntemi için gizli (implicit) parametredir. Diğer bir deyişle yöntemi çağırmak için kullandığımız referans, aynı zamanda gizli parametredir. Gizli parametre yöntemin imzasında tanımlanmaz, gizli olması da zaten bu yüzdendir.

Peki, açık parametre olan “oran” değişkenine yöntem içerisinde direk adıyla erişebiliyorsak, gizli parametreye nasıl erişeceğiz? Bunun için de this anahtar kelimesi kullanılmaktadır. Yöntem içerisinde nesne değişkenlerine erişmek istediğimizde this kelimesini kullanabiliriz. Yani en yukarıda yazdığımız yöntemi aşağıdaki gibi de yazabiliriz.

public void maasArtir(double oran) {
	this.maas += this.maas * oran/100;
}

Yukarıdaki gibi bir kullanımda this anahtar kelimesi ile gizli parametreye erişmiş oluyoruz ve böylece personel1 nesnesinin maaş bilgisine erişiyoruz. Biz maas değişkeninin önüne this yazmasak bile bu kelime otomatik olarak eklenmektedir. Bu şekilde açıkça “this” yazmak, programın okunabilirliğini artırmak ve nesne değişkenleri ile yerel değişkenleri bir bakışta ayırt etmek için faydalı olabilir.

Categories: Java Tags: ,