Welcome to My Blog 👋

Java, Spring Framework, Microservices, Docker, Kubernetes, AWS and Others 🚀
Follow Me
Showing posts with label test - junit. Show all posts
Showing posts with label test - junit. Show all posts

Mockito, Java'da test sınıflarımızı yazarken kullanabileceğimiz bir mock kütüphanesidir. Bu kütüphane ile Java test metotlarımızda test ettiğimiz senaryoların bağımlılıklarını yönetebiliriz. Mockito kütüphanesi kolay öğrenilebilirliği ve kolay kullanılabilirliği ile Java'da en çok kullanılan mock kütüphanesidir.






Yazılım test edilmesi konusunda dikkat edilmesi gereken en büyük nokta bir test metodunda sadece tek bir senaryonun test edilmesi gerektiğidir. Bu konuda yaşanan en büyük sorun test edeceğimiz senaryonun bağımlılıklarıdır. Örneğin bizim test edeceğimiz senaryo bir dış servisi bağımlı olabilir veya bir veritabanı işlemine bağımlı olabilir. Bizim test senaryomuzu bu bağımlılıkları kullanmadan test etmemiz gerekir. İşte bu nokta mock nesneleri devreye giriyor. Mock nesneleri istenilen bir nesneyi birebir taklit eden nesnelerdir. Örneğin bir veritabanı işlemi yapan nesne yerine mock nesnesi kullanabiliriz ve o işlemden beklediğimiz cevabı mock nesnesi ile koda verebiliriz. Bu şekilde her test metodumuzda ilgilendiğimiz senaryoya odaklanabiliriz. Ayrıca gerçek işlemler çok uzun sürebilir. Örneğin bir veritabanı işlemi çok uzun sürebilir. Onlarca yüzlerce testimizin olduğunu düşünürsek yazılımı her test ettiğimizde ciddi süreler beklemek zorunda kalabiliriz. Mock nesneleri işlemleri gerçekten gerçekleştirmediği için çok hızlıdır. Bu şekilde yazılımımızı çok hızlı bir şekilde test edebiliriz.

  • Mock nesnesi istenilen gerçek bir nesneyi birebir taklit edebilir
  • Mock nesnesinin istediğimiz gibi davranmasını sağlayabiliriz


Java'da bir çok mock kütüphanesi vardır. Bunlardan bazıları;


  • Mockito
  • JMock
  • PowerMock


Suite
JUnit framework'ü ile birden fazla test sınıfımızı istediğimiz sıra ile bir arada çalıştırabiliriz. Bunun için Suite yapısı kullanılır. Örneğin aşağıdaki SuiteTest sınıfımızı çalıştırdığımızda ArabaTest ve ArabaTest2 sınıfları sırası ile çalışacaktır.

public class Araba {

    private int hiz;
    private String marka;

    Araba() {

        hiz = 0;
    }

    public int getHiz() {

        return hiz;
    }

    public void hareketEt() {

        hiz++;
    }

    public void kaclaGidiyorum() {

        System.out.println("Hız : " + hiz);
    }

    public boolean opelMi() {

        if (marka.equals("opel")) {
            return true;
        }
        return false;
    }

}

import org.junit.Assert;
import org.junit.Test;

public class ArabaTest {

    @Test
    public void hareketEdiyorMu() {

        Araba araba = new Araba();

        araba.hareketEt();

        Assert.assertNotEquals("Arabanın hızı 0'a eşit!", araba.getHiz(), 0);

        // Diğer assert fonksiyonları
        // Assert.assertArrayEquals
        // Assert.assertEquals
        // Assert.assertFalse
        // Assert.assertNotNull
        // Assert.assertNotSame
        // Assert.assertNull
        // Assert.assertSame
        // Assert.assertThat
        // Assert.assertTrue
    }

}

package deneme;

import org.junit.Test;

public class ArabaTest2 {

    @Test(expected = NullPointerException.class)
    public void hataKontrol() {

        Araba araba = new Araba();

        araba.opelMi();

    }

}


package deneme;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;

@RunWith(Suite.class)
@Suite.SuiteClasses({ ArabaTest.class, ArabaTest2.class })
public class SuiteTest {

}


Ignore
JUnit framework'ünde bulunan @Ignore anotasyonu ile test sınıfımızda çalışmasını istemediğimiz metotları belirtebiliriz. Örneğin bir test sınıfımızda 4 test metodu olduğunu düşünelim ve biz bu metotlardan sadece 3 tanesinin çalışmasını istiyorsak çalışmasını istemediğimiz metodun başına @Ignore anotasyonunu ekleriz.


JUnit framework'ü ile test sınıflarımızı yazarken yanlış senaryoları da test etme ihtiyacı duyabiliriz. Bir senaryoda verilmesi gereken hatanın gerçekten verilip verilmediğini kontrol etmemiz gerekebilir. Bu durumlar için JUnit framework'ü bizim için kullanışlı bir yapı sunuyor. Örnek;

public class Araba {

    private String marka;

    public boolean opelMi() {

        if (marka.equals("opel")) {
            return true;
        }
        return false;
    }

}

import org.junit.Test;

public class ArabaTest {

    @Test(expected = NullPointerException.class)
    public void hataKontrol() {

        Araba araba = new Araba();

        araba.opelMi();

    }

}

JUnit framework'ünde test senaryomuzu çalıştırdıktan sonra beklediğimiz sonuçların olup olmadığını tespit etmek için assert sınıfının fonksiyonlarını kullanırız. Örnek;

public class Araba {

    private int hiz;

    Araba() {

        hiz = 0;
    }

    public int getHiz() {

        return hiz;
    }

    public void hareketEt() {

        hiz++;
    }

    public void kaclaGidiyorum() {

        System.out.println("Hız : " + hiz);
    }

}

import org.junit.Assert;
import org.junit.Test;

public class ArabaTest {

    @Test
    public void hareketEdiyorMu() {

        Araba araba = new Araba();
        
        araba.hareketEt();
        
        Assert.assertNotEquals("Arabanın hızı 0'a eşit!", araba.getHiz(), 0);

        // Diğer assert fonksiyonları
        // Assert.assertArrayEquals
        // Assert.assertEquals
        // Assert.assertFalse
        // Assert.assertNotNull
        // Assert.assertNotSame
        // Assert.assertNull
        // Assert.assertSame
        // Assert.assertThat
        // Assert.assertTrue
    }

}

JUnit, Java dilinde uygulamalarımızı test etmek için kullanabileceğimiz bir test framework'üdür. JUnit web sitesi ve github adresi;


JUnit framework'ünü örneğin maven projesi olarak çalışıyorsak ilgili dependency bilgisini ekleyerek kullanabiliriz. Aynı şekilde jar olarak da projemize ekleyebiliriz. Projemizin yapısına göre projemize ekleyebiliriz.

JUnit Nasıl Çalışır? JUnit Yaşam Döngüsü

JUnit framework'ünde test sınıflarımızı Java ile yazarız. Test sınıflarımızda metotlarımızın başına @Test anotasyonunu ekleyerek kullanırız. JUnit yaşam döngüsünde temel anotasyonlar şunlardır;
  • @BeforeClass (Test sınıfımız çalıştığında en başta sadece bir kez çalışır) 
  • @Before (Her test metodundan önce bir kez çalıştır) 
  • @Test (Test metotlarını belirtmek için kullanılır) 
  • @After (Her test metodundan sonra bir kez çalışır) 
  • @AfterClass (Test sınıfımız çalıştığında en son sadece bir kez çalışır) 



Unit test yazdığımız yazılım her biriminin ayrı ayrı test edilmesidir. Buradaki birim yazılımdaki en küçük parçaya denir. Nesneye yönelik programlama dünyasında en küçük birim sınıflardır. Sınıflar tek başlarına var olabilen ve belirli işleri yapabilen yapılardır. Nesneye yönelik programlamada unit test ile sınıflarımızın yapmaları gereken işleri doğru yapıp yapamadıklarını test ederiz. Unit testte her birim kendi başına test edilmelidir ve bir birim bir başka birime bağlı olmamalıdır. 

Birim testin ana amacı yazılımdaki hataları bulmak değildir. Zaten test mantığının temelinde test kodunun yazılımdan önce yazılması gerekir. Bunun nedeni yazılımdan ne beklediğimizin, hangi durumlarda nasıl çalışması gerektiğinin önceden belirlenmesi gerektiğidir. Eğer bunlar daha önceden belirlenmemişse o yazılımın sağlıklı bir şekilde geliştirilmesi pek mümkün değildir. İşte bu noktada bu durumlar belirlendiğinde bu durumlara göre test sınıflarınında yazılması gereklidir. Daha sonra yazdığımız kod bu belirlediğimiz durumlarda doğru çalışacak kod olmalıdır.

Test sınıflarının bir diğer önemli özelliği de kodumuzu değiştirmemiz gerektiği durumlarda ortaya çıkar. Günümüzde ihtiyaçlar çok sık değişebiliyor. Kod yazıldıktan sonra veya daha kod yazılırken ihtiyaçlar değişebiliyor. Bu durumlarda kodda yaptığımız değişikliğin kodumuzu nasıl etkileyeceği çok büyük problem oluyor. Ancak elimizde daha önceden yazılmış test sınıfları olduğunda yapılan değişiklik sonrası yazılımı test etmek çok kolay olabiliyor.

Bir birimi test ederken yaşanan en büyük problemlerden biride bağımlılıklardır. Örnek olarak bir sınıfın bir metodu veritabanı işlemi yapabiliyor olabilir veya dış bir servisten veri alabiliyor olabilir. Normalde test ederken bu bağımlılıkları da çalıştırırız. Ancak birim test mantığı böyle değildir. Birim testte, test edilen o birimin kodudur. Bağımlılıkların doğru çalışıp çalışmadığı değildir. Bu nedenle birim testte sadece bağımlılıkların doğru bir şekilde çağırılıp çağırılmadığı test edilir. Bu işlem için yazılmış bir çok mekanizma vardır. 

Test sınıflarımızı yazmak için ortaya çıkmış bir çok framework vardır. Bunlardan bazıları;
  • JUnit
  • MSTest
  • NUnit
  • XUnit
  • MbUnit
Birim test yazarken dikkat edilmesi gerekenler;
  • Her test metodunda sadece bir senaryo test edilmelidir.
  • Test metotlarımızı gerekli ortamın hazırlanması, senaryonun çalıştırılması ve sonuçların kontrolü şeklinde bölümlere ayırabiliriz.
  • Test metotlarımızın isimleri test edilen senaryoyu açıklayacak şekilde olmalıdır. Anlamsız bir isimlendirme yerine uzun bir isimlendirme daha iyidir.
  • Test edilen birim diğer birimlerden tamamen bağımsız olmalıdır.
  • Her test metodu diğer test metotlarından bağımsız çalışabilmelidir.