Bu makalemizde C#’ta Junit Testlerin nasıl oluşturulduğunu birkaç örnek ile inceleyeceğiz.
Öncelikle Unit Test nedir konusu ile başlayalım.
Unit test, yazılımda en temel test çeşitidir. Yazılan fonksiyonların çalışıp çalışmadığının testlerini yapmak için kullanılır. Buradaki en temel noktalardan biri, oluşturulan bütün testler birbirinden bağımsız çalışmaktadır ve her testin tek bir sonucu olmalıdır (true / false).
Unit testlerde en büyük avantaj yazılımın geliştirilme hızıdır. Unit testlerin olmadığı bir projeyi düşünelim. Bu projede kullanıcı, bir ürün kaydı yapsın. Proje çalıştığında
- Kullanıcı önce bilgileriyle giriş yapıyor,
- İşlem yapacağı birimi seçiyor,
- Kayıt yapacağı kategoriyi seçiyor,
- Açılan formda gerekli bilgilerini yazıyor
- Kayıt butonuna basıyor
Unit testlerin olmadığı bir projede yazılım geliştirici, yazılan kayıt fonksiyonu hemen arayüz katmanına bağlandığı taktirde runtime’da oluşacak hataların tespiti için bu işlemlerin hepsini tamamlayıp kayıt butonuna bastığında hatayla karşılaşacaktır. Hatayı düzeltip tekrar çalıştıracak, aynı işlemleri tekrar yapacak ve başka bir hatayla karşılaşabilecektir. Bu, yazılımcıya projenin ilerleyen aşamalarında büyük zaman kaybı yaşatmaktadır.
Unit testlerin en büyük avantajı da burada kendini göstermektedir. Bir üst satırda yazdığım örneği unit testlerle gerçekleştiren bir yazılımcı, bu işlemlerin hiçbirini yapmadan kendi oluşturduğu dummy datalarla bu hataları arayüz katmanına bağlama işlemini yapmadan alacak, testlerinin tümü başarıyla çalıştıktan sonra arayüz katmanına bağlama işlemini yapacak ve zaman kaybını önleyecektir.
Unit test oluştururken yapılması gereken, sadece kodun çalışacağı değerlerde değil çalışmayacağı değerlerin de parametrelerde gönderilip verilen hataların düzenlenmesidir. Örneğin bir fonksiyon içinde bir yerde bölme işlemi geçiyorsa parametreden bu bölme işleminde böleni 0 yapan bir değer gönderdiğimizde hata vereceğini biliyorsak bu hatanın sonucunda sistemin nasıl bir sonuç üreteceğini de görmemiz gerekmektedir. Bunun için de bir test yazmamız gerekecektir. Classlarımız tamamlandığında testlerinin de oluşturulup classlardaki tüm fonksiyonların testlerini başarıyla tamamlamalarını sağladıktan sonra bir sonraki class’ı kodlamaya başlamak gerekmektedir.
Peki Unit Test’in avantajlarını hızlıca maddelemek istersek:
- Yazılan kodun her satırının başka bir kod (test kodu) tarafından otomatik olarak test edilmesini sağlar.
- Kodun anlaşılmasını kolaylaştırır.
- Daha hızlı yazılım geliştirmeyi sağlar.
- Koddaki hata oranını azaltır.
- Kodların kalitesinin artmasını sağlar.
- Hataların çabuk tespit edilip düzenlenmesini sağlar.
Şimdi .Net’te (C#) Unit Test’in nasıl yapıldığını inceleyelim.
.Net’te unit testi için önce testini yapacağımız sınıf ve fonksiyonu bir Class Library projesinde oluşturalım.
Örnek sınıfımızda parametre olarak 2 sayı gönderiyoruz ve bu sayıları kullanarak çarpma ve bölme işlemlerini gerçekleştiriyoruz.
- public class Islem
- {
- public Islem() { }
- public Islem(int sayi1, int sayi2)
- {
- this.Sayi1 = sayi1;
- this.Sayi2 = sayi2;
- }
- public int Sayi1 { get; set; }
- public int Sayi2 { get; set; }
- public int Carp()
- {
- return this.Sayi1 * this.Sayi2;
- }
- public int Bol()
- {
- return this.Sayi1 / this.Sayi2;
- }
- }
Sınıfımızı oluşturduk. Şimdi test projemizi oluşturalım. Bunun için Solution Explorer’dan Add -> New Project ile yeni bir proje ekliyoruz ve C# Test Projesini seçiyoruz.
Test projesi oluşturulduğunda Solution Explorer’ın görüntüsü aşağıdaki gibidir.
Visual Studio, UnitTest1.cs isminde hazır bir Unit Test dosyası oluşturuyor. Şimdi bunu silelim ve yeni bir unit test oluşturmak için hazırladığımız Islem sınıfına gidelim, fonksiyonumuza sağ tıklayıp “Create Unit Tests…” linkine tıklayalım.
Açılan ekranda hangi test projesinde testimizi yapacağımızı ve hangi fonksiyonları test edeceğimizi seçiyoruz ve “OK” butonuna tıklıyoruz. Visual Studio, seçimimize göre test classını oluşturacaktır.
Oluşturulan IslemTest1.cs’nin test fonksiyonları ilk oluşturulduğunda aşağıdaki gibidir.
- /// <summary>
- ///A test for Bol
- ///</summary>
- [TestMethod()]
- public void BolTest()
- {
- int sayi1 = 0; // TODO: Initialize to an appropriate value
- int sayi2 = 0; // TODO: Initialize to an appropriate value
- Islem target = new Islem(sayi1, sayi2); // TODO: Initialize to an appropriate value
- int expected = 0; // TODO: Initialize to an appropriate value
- int actual;
- actual = target.Bol();
- Assert.AreEqual(expected, actual);
- Assert.Inconclusive("Verify the correctness of this test method.");
- }
- /// <summary>
- ///A test for Carp
- ///</summary>
- [TestMethod()]
- public void CarpTest()
- {
- int sayi1 = 0; // TODO: Initialize to an appropriate value
- int sayi2 = 0; // TODO: Initialize to an appropriate value
- Islem target = new Islem(sayi1, sayi2); // TODO: Initialize to an appropriate value
- int expected = 0; // TODO: Initialize to an appropriate value
- int actual;
- actual = target.Carp();
- Assert.AreEqual(expected, actual);
- Assert.Inconclusive("Verify the correctness of this test method.");
- }
Burada dikkat etmemiz gereken en önemli nokta, TestMethod() attribute’udur. Buna sahip tüm methodlar test methodlarıdır diyebiliriz.
Islem sınıfının Carp() methodunun testinin yazılacağı için söylemiştik. Islem sınıfından bir nesne oluşturmak için 2 tane int değere ihtiyacımız vardır. Bu değerleri birer değişken ile (sayi1, sayi2) otomatik oluşturuluyor. Bunun sebebi, testlerde gönderdiğimiz parametreleri daha iyi görebilmektir.
İşlem tamamlandıktan sonra bir sonuç dönmesini bekleyeceğiz. Bu test için sonucun kaç olmasını bekliyorsak onu expected değişkenimize atıyoruz.
Şimdiye kadar oluşturulan değişkenler, test işleminde gönderilen ve alınan sonuçları takip etmemizi kolaylaştıracaktır.
Değişkenleri oluşturduktan sonra işlemlerimizi yaptık ve expected değişkenimize işlemimizin fonksiyondan gelen soncunu atadık.
Test projesinin kontrol noktasına gelelim. Assert sınıfı.
Testimizin çalışıp ürettiği sonuca göre doğru yanlışlığını bu sınıfın methodları ile kontrol etmekteyiz. Assert sınıfının bazı methodlarına göz atalım.
AreEqual
|
Parametredeki değerlerin birbirine eşit olmasını kontrol eder.
|
AreNotEqual
|
Parametredeki değerlerin birbirine eşit olmamasını kontrol eder.
|
AreNotSame
|
Parametrelerdeki değerlerin aynı olmamasını kontrol eder.
|
AreSome
|
Parametrelerdeki değerlerin aynı olmasını kontrol eder.
|
Equals
|
Parametrelerdeki değerlerin eşit olmasını kontrol eder.
|
Fail
|
Koşulsuz kontrol sağlamak
|
IsFalse
|
Parametredeki değerin false olmasını kontrol eder.
|
IsNotNull
|
Parametredeki değerin null olmamasını kontrol eder.
|
IsNull
|
Parametredeki değerin null olmasını kontrol eder.
|
IsTrue
|
Parametredeki değerin true olmasını kontrol eder.
|
Temel anlamda kullanılan test methodları bunlardır. Şimdi örneğimizde kullanıdığımız methoda bakalım.
- Assert.AreEqual(expected, actual);
sonuc, gercekSonuc’a eşitse test başarıyla sonuçlanacak, hata verecektir.
Şimdi test kodumuzu şu şekilde düzenleyelim:
- [TestMethod()]
- public void CarpTest()
- {
- int sayi1 = 10; // TODO: Initialize to an appropriate value
- int sayi2 = 20; // TODO: Initialize to an appropriate value
- Islem target = new Islem(sayi1, sayi2); // TODO: Initialize to an appropriate value
- int expected = 200; // TODO: Initialize to an appropriate value
- int actual;
- actual = target.Carp();
- Assert.AreEqual(expected, actual);
- }
Şimdi CarpTest() isimli test methodumuzu çalıştıralım. Bunun için “Run Tests in Current Context” butonuna tıklıyoruz. Hemen sağında “Run All Tests in Current Context” butonuna tıklayarak tüm testleri çalıştırabiliriz.
Testi çalıştırdıktan sonra Test Results ekranında aşağıdaki sonucu göreceğiz.
Test sonuçloarını bu ekrandan takip edebilmekteyiz.
Şimdi Carp() methodumuzun kodunu şu şekilde düzenliyoruz.
- [TestMethod()]
- public void CarpTest()
- {
- int sayi1 = 10; // TODO: Initialize to an appropriate value
- int sayi2 = 220; // TODO: Initialize to an appropriate value
- Islem target = new Islem(sayi1, sayi2); // TODO: Initialize to an appropriate value
- int expected = 200; // TODO: Initialize to an appropriate value
- int actual;
- actual = target.Carp();
- Assert.AreEqual(expected, actual);
- }
Sonucun 200 çıkmasını bekliyoruz fakat 2200 çıkacaktır ve testten başarısız sonuç alacağız. Testi çalıştırdığımızda Test Results ekranı aşağıdaki gibi gelecektir.