Skip to main content
Java Unit Test Nasıl Yazılır

Java Unit Test Nasıl Yazılır: JUnit, Mockito, Spring Boot

Bu yazıda, JUnit ve Mockito kullanarak, yazılım geliştirmenin önemli bir parçası olan unit testlerin bir Spring Boot uygulaması içerisinde nasıl kullanılacağından bahsedeceğim. Bu içerik, unit (birim) test nedir, JUnit ve Mockito nedir, test metotlarının isimlendirme standartları, test annotationları ve unit test uygulamalarını içermektedir.

Unit (Birim) Test Nedir?

Unit Test, uygulamanın içerisindeki belirli işlevlerin sağlıklı olarak gerçekleşip gerçekleşmediğinin kontrol edilmesi için önemlidir. Unit test kavramı, uygulamanın test edilebilir en küçük parçasını kapsar. Bu testler, kodun doğruluğunu sağlamak ve gelecekteki değişikliklerin mevcut kodu bozup bozmadığını belirlemek için kullanılır.

JUnit Nedir?

JUnit, Java tabanlı bir birim test çerçevesidir. Yazılım projelerinde birim testlerin otomatik olarak yürütülmesini, sonuçların analiz edilmesini ve test süreçlerinin yönetilmesini sağlar. Kodun beklenen davranışı sergileyip sergilemediğini doğrulamak amacıyla kullanılır.

Mockito Nedir?

Mockito, gerçek nesnelerin yerine kullanılabilen sahte nesneler (mocks) oluşturarak birim testlerin izole edilmesini sağlar. Bu sayede bir sınıfın bağımlılıklarını test etmek daha kolay hale gelir. Mockito, yazılım geliştirme sürecinde test odaklı yaklaşımların uygulanmasına yardımcı olur ve kodun kalitesini artırır.

Unit Test Annotationları ve Assertions

  • @Test: JUnit testlerinin başlangıç noktasını işaretler. Bir test metodu olduğunu belirtir ve bu metotlar JUnit tarafından çalıştırılır.
  • @RepeatedTest: Yazılan testi birden fazla çalıştırmak istediğimiz durumlarda kullanılır. Parametre olarak testin çalışma sayısını alır.
  • @DisplayName: IDElerin testleri monitör etmeye yarayan sekmelerinde testlerin görüneceği ismi belirlemeye yarar.
    @Test
    @DisplayName("Unsorted List to Sorted List Case")
    @RepeatedTest(10)
    public void whenCallSortListWithIntegerList_shouldReturnSortedList() {

       ...
    }

Bu örnekte, whenCallSortListWithIntegerList_shouldReturnSortedList fonksiyonunu test olarak işaretledik, IDE’de “Unsorted List to Sorted List Case” olarak görünmesini sağladık ve testin 10 kere çalışmasını istedik.

 

  • @BeforeEach / @BeforeAll: @BeforeAll annotation’ı, test sınıfının tüm test metodları çalışmadan önce bir kez çağrılır. @BeforeEach annotation’ı ise, her test metodu çalışmadan önce çağrılır.
  • @AfterEach / @AfterAll: Before annotationlarına benzer şekilde, @AfterAll annotation’ı tüm test metodları çalıştıktan sonra bir kez çağrılır ve @AfterEach annotation’ı her test metodu çalıştıktan sonra çağrılır.
    @BeforeEach
    public void setUp() {
        listSortService = new ListSortService();
    }
    @AfterEach
    public void tearDown() {
        listSortService = null;
    }
Bu örnekte, her bir test çalıştırmadan önce yeni bir ListSortService oluşturup, her bir test tamamlandıktan sonra listSortService değişkenini sıfırladık.
  • assertEquals(expected, actual): Beklenen değerle gerçek değeri karşılaştırır. Eğer bu iki değer birbirine eşit değilse bir hata fırlatır.
  • assertTrue(condition): Belirtilen koşulun doğru olup olmadığını kontrol eder. Eğer koşul doğru değilse bir hata fırlatır.
  • assertFalse(condition): Belirtilen koşulun yanlış olduğunu kontrol eder. Eğer koşul doğru ise bir hata fırlatır.
  • assertNotNull(object): Belirtilen nesnenin null olmadığını kontrol eder. Eğer nesne null ise bir hata fırlatır.
  • assertNull(object): Belirtilen nesnenin null olduğunu kontrol eder. Eğer nesne null değilse bir hata fırlatır.
  • assertThrows(exceptionClass, executable): Belirtilen bir metotun belirli bir türde bir istisna fırlatıp fırlatmadığını kontrol eder. Eğer belirtilen metot istisna fırlatmazsa veya farklı bir türde bir istisna fırlatırsa bir hata fırlatır.
    @Test
    public void whenDivisionByZero_shouldThrowsArithmeticException() {
        assertThrows(ArithmeticException.class, () -> Calculator.divide(10, 0));
    }
    @Test
    public void whenSumTwoNumbers_shouldEqualsSumOfTwoNumbers() {
        int result = Calculator.add(3, 5);
        assertEquals(8, result);
    }
Bu örnekte, whenDivisionByZero_shouldThrowsArithmeticException testinde 10’u 0’a bölmeye çalıştığımızda ArithmeticException fırlatılma durumunu ve whenSumTwoNumbers_shouldEqualsSumOfTwoNumbers testinde, 3 ve 5 sayısını toplayan fonksiyonumuzun 8 değerini döndürüp döndürmediğini kontrol ettik.
  • @Mock / @InjectMock: @Mock annotation’ı, Mockito tarafından kullanılan bir annotation’dır ve mock nesnelerini oluşturmak için kullanılır. @InjectMock annotation’ı, bir mock nesnesini bir sınıfa enjekte etmek için kullanılır. Bu nedenle, @Mock ile oluşturulan nesne ve bu nesnenin enjekte edildiği sınıf arasındaki ilişkiyi belirtmek önemlidir.
@Mock
private UserService userService;

@InjectMocks
private UserController userController;

Bu örnekte, userService adında bir mock nesne oluşturduk ve bu nesneyi userController sınıfına enjekte ettik.

Spring Boot ile Unit Test Uygulaması

Yazının buraya kadar olan kısmında JUnit, Mockito ve unit test kavramından bahsettik. Bu bölümde, bir Spring Boot uygulaması için örnek unit testler yazacağız.

İlk olarak uygulamamızın pom.xml dosyasına gerekli dependencyleri ekliyoruz:

        <!-- Mockito -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.12.4</version>
            <scope>test</scope>
        </dependency>
        <!-- JUnit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.1</version>
            <scope>test</scope>
        </dependency>
Bağımlılıkların yüklemeleri tamamlandıktan sonra testini yazacağımız servisi yazmaya başlayabiliriz. Bu serviste, gönderilen sayı listesini küçükten büyüğe sıralayan bir metot oluşturacağız:
package com.onurilyastokay.unittestexample.services;
import java.util.ArrayList;
import java.util.Collections;
public class ListSortService {


    public ArrayList<Integer> sortList(ArrayList<Integer> list) {
        Collections.sort(list);
        return list;
    }
}

Unit Test Oluşturma ve İsimlendirme Standartları

Servisimiz hazır olduğuna göre, tekrar test kısmına geri dönebiliriz. Bu testte, sıralanmamış dummy bir datayı sortList metoduna göndererek metodun döndürdüğü sıralanmış listenin doğruluğunu kontrol edeceğiz. İlk olarak test dosyamızı oluşturalım:

Spring Boot proje yapısında, src klasörünün altında main ve test olmak üzere iki klasör bulunur. main klasörü uygulamamızın kodlarını içerirken test klasörü de bu kodların testlerini içerir (main klasöründe test, test klasöründe uygulama kodları yazmak da mümkündür fakat daha huzurlu bir dünya için yazmamanız tavsiye edilir.). Oluşturduğum ListSortService.java dosyası benim projemde “src/main/java/com/onurilyastokay/unittestexample/services” pathinde bulunuyor. Bu durumda ListSortServiceTest.java dosyamı “src/test/java/com/onurilyastokay/unittestexample/services” pathinde oluşturabilirim.

 

Testlerde, isimlendirme standardı olarak when ve should keywordleri kullanılır. Test fonksiyonları isimlendirilirken test senaryosunu açıklayan bir isim belirlenmelidir. Örneğin, bizim senaryomuzda bir sayı listesiyle sortList metodu çağırıldığında sıralanmış bir liste dönmesini bekliyoruz. Buna uygun olarak, whenCallSortListWithIntegerList_shouldReturnSortedList gibi bir isim kullanabiliriz.

İlk Unit Testimizi Yazalım

Bu bölümde, ListSortService’deki sortList metodu için unit test yazacağız. Bu metodu test etmek için sırasız bir liste örneği oluşturup sortList metoduna göndereceğiz. Sırasız listenin bir sıralı örneğini oluşturarak metottan dönen değer ile sıralı örneği karşılaştırarak dönen değerin doğrulunu test edeceğiz:

package com.onurilyastokay.unittestexample.services;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.ArrayList;
import java.util.Arrays;

import org.junit.jupiter.api.Test;

public class ListSortServiceTest {

    @Test
    public void whenCallSortListWithIntegerList_shouldReturnSortedList() {
        ArrayList<Integer> inputList = new ArrayList<>(Arrays.asList(3, 1, 2));
        ArrayList<Integer> expectedList = new ArrayList<>(Arrays.asList(1, 2, 3));

        ArrayList<Integer> sortedList = new ListSortService().sortList(inputList);

        assertEquals(expectedList, sortedList);
    }
}

Bu örnekte, inputList adında ve 3,1,2 değerlerini içeren bir ArrayList oluşturduk. Bu ArrayList’i metoda gönderdiğimizde dönmesini beklediğimiz değerleri (1,2,3) expectedList ArrayList’inde tanımladık. Sonrasında, inputList’i sortList metodumuza gönderdik ve metottan dönen değeri beklediğimiz değerlerle karşılaştırdık. Test sonucu:

java unit test ornegi

Mock Annotation Kullanarak Unit Test Yazma

Bu bölümde, @Mock annotation’ı kullanarak basit bir unit test yazacağız. Öncelikle test için gerekli ortamı hazırlayalım:

  • User model ve UserService servisi oluşturulmalı.
  • User, id ve name özelliklerine sahip olmalı.
  • id ve name özellikleri getter/setterlara sahip olmalı.
  • Constructor üzerinden User nesnesi yaratılabilmeli.
  • UserService içerisinde, User’ın constructor’ını çağıran createUser adında bir metot bulunmalı.

User.java:

package com.onurilyastokay.unittestexample.models;

public class User {
    
    private Integer id;
    private String name;


    public User(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

UserService.java:

package com.onurilyastokay.unittestexample.services;

import com.onurilyastokay.unittestexample.models.User;

public class UserService {

    public User createUser(Integer id, String name) {
        return new User(id, name);
    }
}

Bu uygulamanın test kısmında, createUser metoduna id ve name bilgisi göndererek bir User nesnesi oluşturacağız. Sonrasında, oluşturduğumuz nesnenin getterlarını kullanarak gönderdiğimiz id ve name bilgisinin doğruluğunu kontrol edeceğiz. “src/test/java/com/onurilyastokay/unittestexample/services” pathinin altına UserServiceTest.java dosyamızı oluşturarak testimizi yazalım.

UserServiceTest.java:

package com.onurilyastokay.unittestexample.services;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;
import org.mockito.Mock;

import com.onurilyastokay.unittestexample.models.User;

public class UserServiceTest {
    
    @Mock
    private User mockedUser;

    @Test
    public void whenCreateUser_shouldEqualsWithIdAndNameParameters() {
        UserService userService = new UserService();
        String name = "Onur";
        int id = 1;
        
        mockedUser = userService.createUser(id, name);
        
        assertEquals(name, mockedUser.getName());
        assertEquals(id, mockedUser.getId());
    }
}

Bu kod örneğinde, @Mock annotation’ı kullanılarak mockedUser isminde dummy bir User nesnesi oluşturduk. Sonrasında id’si 1 olan ve ismi Onur olan bir User oluşturarak mockedUser değişkenine atadık. createUser metoduna parametre olarak geçtiğimiz id ve name bilgisiyle oluşturulan User’ın id ve name bilgisini assertEquals ile karşılaştırdık.

Test Sonucu:

mock unit test java

Yaptığımız örneklerde assertEquals kullanarak gönderilen ve alınan verileri karşılaştırdık. Örneğimizi biraz daha genişleterek hatalı kullanım durumlarını da test eden bir uygulama hâline getirelim:

Bu testte parametre olarak gönderdiğimiz id’ye negatif değerli bir sayı atayarak User oluşturabiliriz. Kod içerisinde de bu durumu kontrol eden bir yapı bulunmuyor. UserService.java dosyasında ufak bir değişiklik yaparak negatif id’li kullanıcı oluşturulmasını engelleyebiliriz.

public User createUser(Integer id, String name) {
        if (id < 0) {
            throw new IllegalArgumentException();
        }
        return new User(id, name);
    }

Bu güncellemeden sonra id değerinin negatif olması durumunda uygulamamızın IllegalArgumentException fırlatmasını bekliyoruz. id parametresinin negatif değer olarak gönderildiği bir unit test yazarak kodun doğru çalışıp çalışmadığını kontrol edebiliriz.

@Test
public void whenCreateUser_shouldIdCannotBeLessThanZero() {
    UserService userService = new UserService();
    String name = "Onur";
    int id = -5;
    assertThrows(IllegalArgumentException.class, () -> userService.createUser(id, name));
}

Burada idsi -5 olan ve ismi Onur olan bir user oluşturmaya çalışıyoruz. createUser metodu IllegalArgumentException hatası fırlatırsa createUser metoduna eklediğimiz if bloğunun istediğimiz gibi çalışıyor demektir. Bu durumda, test başarılı olarak dönecektir.

Test Sonucu:

Java Unit Test Assertions

 

Bu yazıda, JUnit, Mockito ve Spring Boot kullanarak basit bir unit test uygulaması geliştirdik. Umarım faydalı olmuştur. Projenin kaynak kodlarına GitHub hesabımdan ulaşabilirsiniz: GitHub | java-unit-test

2 thoughts to “Java Unit Test Nasıl Yazılır: JUnit, Mockito, Spring Boot”

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir