JUnit platformu, Java sanal makinesi (JVM) üzerindeki test süreçlerini başlatmak, yönetmek, raporlamak için kullanılır.
Java’da Unit Test ve Integration Test
- Unit test bir yazılımın bir parçasını, bir method ya da sınıfı daha doğrusu küçük bileşenlerin test edilmesi için kullanılır. Yazılımın her bir parçasının beklendiği gibi çalışıp çalışmadığını kontrol etmek için kullanılır.
public class Hesaplama {
public static int topla(int a, int b) {
return a + b;
}
public static int cikar(int a, int b) {
return a - b;
}
}
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class HesaplamaTestTest {
@Test
public void testTopla() {
assertEquals(5, Hesaplama.topla(2, 3));
}
@Test
public void testCikar() {
assertEquals(2, Hesaplama.cikar(5, 3));
}
}
Integration test ise birden fazla bileşenin biraraya gelerek bir süreci doğru şekilde gerçekleştirdiğini doğrulamak için yapılır. Bir uygulamada önce bir rapor girişi ardından da ilgili yerlerin mail ile bilgilendirilmeleri süreci olsun. Bu sürecin doğru bir şekilde uygulanıp uygulanmadığını görmek için integration test yapılır.
Spring boot, JUnit ve Mockito kullanarak unit testler ve integration testler oluşturmamıza imkan tanır.
Test yaparak daha az bug içeren ve daha yüksek güvenilirlik sunan uygulamalar geliştirebiliriz.
Unit test özetle kodun bir parçasının doğruluğunun test edilmesidir. Integration test ise birden fazla bileşenin belirli bir plana göre test edilmesidir. Bir sürecin test edilmesidir. Yazılımı oluşturan parçalar bir arada uyumlu bir şekilde çalışıyor mu sorusunun cevabıdır.
Spring boot projemizde Junit kullanmak için JUnit-jupiter bağımlılığını projeye eklemeliyiz. Scope test diyerek bu bağımlılığın sadece test amacıyla kullanılacağını belirtiriz.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.3</version>
<scope>test</scope>
</dependency>
Assertions sınıfı içinde;
- assertEqual, assertNotEqual, assertNull, assertNotNull, assertSame, assertNotSame, assertTrue, assertFalse, assertThrow, assertDoesNotThrow vb. methodlar bulunur.
Test sınıfı içinde diyelim ki testEqualsFunctionality isimli bir method olsun. Bu method içinde test edeceğimiz sınıfa ait bir nesne oluştururuz ve
assertEquals(6, JUnitOrnegi.add(1, 3), "1 + 3 must be 4");
gibi bir kontrol yaparız. Test sınıfı içinde herbir method öncesinde ya da sadece bir kez çalıştırılabilecek kod parçaları için @BeforeEach, @AfterEach, @BeforeAll, @AfterAll annotation’ları kullanılabilir.
Custom Display Name
Test sınıfını çalıştırdığımızda output içinde çalıştırılan method isimlerini görürüz. Burada yazılımcı olmayan kişiler için daha anlaşılır isimlendirmeler yapılabilir. JUnit Jupiter API içinde DisplayNameGenerator sınıfını kullanırız. Test sınıfının başına şu annotation’ı ekleriz.
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
Bu şekilde test method isminin içindeki altçizgiler boşluklarla değiştirilir. Bu şekilde daha anlaşılır bir isim üretilir.
Test sınıfı üzerinde @DisplayNameGeneration annotation’ı kullanılmadan her bir method için de isimlendirme yapılabilir. Bunun için @DisplayName(“kullanılacak isim”) annotation’ı kullanılır.
assertArrayEquals
İki dizinin eşit olup olmadığını kontrol eder. Elemanların sırası aynı olmalıdır.
DisplayName("Testing Array Equality")
@Test
public void arrayEqualsTes() {
int[] mevcutDizi = {10,20,30};
int[] yeniDizi = getArray();
assertArrayEquals("Diziler esit olmalidir!", mevcutDizi, yeniDizi);
}
private int[] getArray() {
return new int[]{10,20,30};
}
assetIterableEquals
Iterable türündeki veri yapılarını (List, Set, vb. ) karşılaştırmak için kullanılır. Elemanların sırası önemli değildir. Sadece aynı olmaları yeterlidir. assertArrayEquals dizileri, assertIterableEquals iterable türündeki yapıları test etmede kullanılır.
assertLineMatch
İki String listesi karşılaştırılır. Sıralama önemlidir. Regex kullanılarak belli bir desende de karşılaştırma yapılabilir.
assertLinesMatch("Satirlar eslesmelidir!", beklenenListe, mevcutListe,
"Merhaba", ".*", "Nasilsin\\?");
Test Methodlarının Sıralanması
Test sınıfı üzerinde @TestMethodOrderer annotation’ı kullanılır.
Test methodlarını DisplayName içindeki alfabetik sıralamaya göre çalıştırmak istiyorsak;
@TestMethodOrderer(MethodOrderer.DisplayName.class)
Test methodlarında DisplayName annotation’ı kullanılmıyorsa;
@TestMethodOrderer(MethodOrderer.MethodName.class)
Bütün testlerin herhangi bir sıralamaya bağlı olmaksızın başarılı olacağını düşünüyorsak;
@TestMethodOrderer(MethodOrderer.Random.class)
Sıralamayı doğrudan methodlar üzerinde @Order annotation’ı kullanarak da yapabiliriz. En düşük numara – negatifler dahil – en yüksek önceliğe sahiptir. Aynı order sırası olursa burada JUnit algoritması bir methoda öncelik verecektir. Test sınıfı üzerinde de şu şekilde annotation eklenir;
@TestMethodOrderer(MethodOrderer.OrderAnnotation.class)
Code Coverage Reports With Maven
Bilgisayarda maven yüklü olsun. Terminalde mvn -version çalıştır. Terminalde projenin bulunduğu klasöre git. mvn clean test komutunu çalıştır. Maven default olarak JUnit test sınıflarını bulamaz. Projenin pom.xml dosyasına git. build altına maven-surefire-plugin ekle. Yeniden mvn clean test komutunu çalıştır. Test sonuçları görüntülenecektir.
Sonuçları html olarak görüntülemek için maven-surefire-report-plugin’i ekle. Tekrar mvn clean test komutunu çalıştır. Sonra mvn site -DgenerateReports=false komutunu çalıştır. Proje klasörüne git. target/site altında surefire-report.html dosyası oluşmuş durumdadır.
Koşullu Test(Conditional Test)
Bir test methodunun belli bir dönem için devre dışı kalmasını istiyorsak @Disabled annotation’ı kullanılır. Belirli bir işletim sistemi üzerinde çalışmasını istiyorsak @EnabledOnOs(OS.isletim_sistemi) annotation’ı kullanılır. Belirli bir java sürümü üzerinde çalışmasını istiyorsak @EnabledOnJre annotation’ı kullanılır. Java sürümü belli bir aralıktaysa testi çalıştırmak için @EnabledForJreRange annotation’ı kullanılır. Min ya da max değerleri atanır.
Belirli bir environment variable değeri kontrol edilip çalıştırılabilir. @EnabledIfEnvironmentVariable(name=”key”, matches =”value”)
System property değeri kontrol edilip çalıştırılabilir. @EnabledIfSystemProperty(name=”key2″, matches =”value2″)
Test Driven Development (TDD)
Geleneksel programlama mantığı şu şekilde ilerler. Önce tasarım yapılır, sonra kod yazılır en sonunda da testler yapılır. TDD mantığında ise önce başarısız testler yazılır ardından bu testi düzgünce çalıştıracak şekilde kodlar yazılır ve son olarak da kod üzerinden bir iyileştirme yapılıp yapılamayacağı araştırılarak refactoring yapılır.