İçerikler :

@After @AfterClass @Before @BeforeClass @Before ve @After Kullanılan Basit Bir Örnek @Ignore @Parameters @Test assertThat İle Kullanılabilen Özellikler Assume Assume İle Sadece Windows İçin Çalışacak Test.. Basit Bir JUnit Test Örneği Basit Bir Parametrik Test Örneği Basit Bir Test Suite Örneği Basit Bir Test Suit Sınıfı Örneği Category Exception Beklenen Testler İki Sayıyı Toplayan Basit Bir Theory Örneği JUnit junit.org JUnit 5 ile Basit Bir Test Örneği JUnit 5 ile TemporaryFolder Kullanımı JUnit assert Methodları Mockito Rulet Çemberi Birim Testi Test Methodlarının Sıralı Çalıştırılması Test Suit Theory

Bu Sayfayı Paylaş:

Kavram

JUnit

Tanım: Java'da birim test yazılması ve çalıştırılmasını sağlayan açık kaynak kodlu bir framework

Kaynak

junit.org

JUnit projesinin ana web sitesi

Kavram

@Test

Tanım: JUnit'de, bir fonksiyonun test amacıyla yazıldığı belirtmek için kullanılan annotation

Örnek

Basit Bir JUnit Test Örneği

Aşağıdaki gibi bir sınıf olsun:
public class SimpleTest {
	public int topla(int a, int b){
		return a+b;
	}
}
Kod sadece verilen iki sayıyı toplamaktadır. topla method'unun doğru çalıştığını test etmek için aşağıdaki gibi bir test sınıfı yazılabilir:
import org.junit.*;
import static org.junit.Assert.*;
public class Tester {
	@Test
	public void testTopla(){
		SimpleTest simple=new SimpleTest();
		int c=simple.topla(1,2);
		assertEquals(3, c);
	}
}
@Test annotation'ı bir fonksiyonun test kodu içerdiğini belirtir. Eclipse vb.. bir çok editor bu ifadeyi doğrudan çalıştırmanızı sağlayacak desteği bulunmkatadır.
Test fonksiyonu (testTopla) içinde SimpleTest sınıfının nesnesi yaratılıp, 1 ve 2 sayısı toplanmakta ve c'ye atanmaktadır. C değerinin 3 olmasını bekliyoruz aksi takdirde hata var demektir. JUnit'de koşulları test etmek için assert ile başlayan çok sayıda fonksiyon bulunur. Biz değerin 3 olmasını kontrol etmek istediğimizden assertEquals fonksiyonunu kullanıyoruz

Veri

JUnit assert Methodları

JUnit'de bir değerin veya nesnenin, beklendiği gibi olup olmadığını test amacıyla kullanılan , assert ile başlayan en önemli method'lar ve ne işe yaradıkları aşağıdaki gibidir:
  • assertEquals : Değer ile beklenen değerin eşitliğini kontrol eder. Eşit ise test başarılıdır
  • assertNotEquals : Değer ile beklenen değerin eşit olmamasını kontrol eder. Eşit değilse test başarılıdır
  • assertNull : Bir nesnenin null olmasını kontrol eder. Null ise test başarılıdır.
  • assertNotNull : Bir nesnenin null olmamasını kontrol eder. Null değilse test başarılıdır.
  • assertTrue : Değerini true olmasını kontrol eder. Değer true ise test başarılıdır
  • assertFalse: Değerini false olmasını kontrol eder. Değer false ise test başarılıdır
  • assertSame : İki nesnenin aynı olup olmadığını (aynı nesneye refrans vermesi) kontrol eder. İki nesne aynı ise test başarılıdır
  • assertNotSame : İki nesnenin aynı olup olmadığını (aynı nesneye refrans vermesi) kontrol eder. İki nesne aynı değil ise test başarılıdır
  • assertThat : Macther ile belirtilen koşula uyup uyulmadığını kontrol eder. Hamcrest kütüphanesi desteklenmektedir
  • assertArrayEquals : İki dizinin eşitliğini kontrol eder. Eşit ise test başarılıdır


Kavram

@Before

Tanım: JUnit'de, bir test sınıfında, birden fazla test methodunun ihtiyaç duyacağı aynı değer ve nesneleri, testler çalışmadan önce yaratmak için kullanılan annotation.

Kavram

@After

Tanım: JUnit'de, bir test sınıfında, birden fazla test methodunun çalışmasından sonra ortak bazı kodların çalışması için kullanılan annotation. Örneğin bazı kaynakların serbest bırakılması vb.. bu method ile yapılır.

Kavram

@BeforeClass

Tanım: JUnit'de, bir test sınıfındaki test method'ları çalıştırılmaya başlamadan önce yapılması gereken işlerin yapıldığı method'u tanımlamak için kullanılan annotation

Kavram

@AfterClass

Tanım: JUnit'de, bir test sınıfındaki test method'larının hepsinin tamamlanmasından sonra yapılması gereken işlerin yapıldığı method'u tanımlamak için kullanılan annotation

Örnek

@Before ve @After Kullanılan Basit Bir Örnek

Aşağıdaki gibi bir sınıfınız olsun :
public class SimpleTest {
	public int topla(int a, int b){
		return a+b;
	}
	public int carp(int a, int b){
		return a*b;
	}
}
Bu sınıf içindeki topla ve carp method'larını test eden sınıf aşağıdaki gibi yazılabilir:
import org.junit.*;
import static org.junit.Assert.*;
public class Tester {	
	SimpleTest simple=null;	
	@Before
	public void setUp(){
		simple=new SimpleTest();
	}	
	@After
	public void tearDown(){
		simple=null;
	}		
	@Test
	public void testTopla(){
		int c=simple.topla(1,2);
		assertEquals(3, c);
	}	
	@Test
	public void testCarp(){
		int c=simple.carp(1,2);
		assertEquals(2, c);
	}	
}
Yukarıdaki örnekte, SimpleTest nesnesi setUp içinde yapılmaktadır. Bu şekilde her test öncesi nesne yaratılır ve test sonrası nesne null haline getirilir

Veri

Exception Beklenen Testler

Bazı testler, exception oluşup oluşmadığını test etmek amacıyla yapılabilir. Örneğin pozitif bir int değeri alması gereken bir fonksiyonda, negatif bir sayı verildiğinde IllegalArgumentException fırlatması gerekiyor ise, test negatif bir sayı ile çağrırarak yapılabilir.
Örneğin aşağıdaki gibi bir kod IllegalArgumentException fırlatılmasını bekliyor anlamına gelir:
@Test(expected = IllegalArgumentException.class)
public void negatifTest(){
	Simple.isle(3,-1);
}
Simple sınıfındaki isle methodu , IllegalArgumentException fırlatmalıdır. Eğer IllegalArgumentException oluşmaz ise test başarısız olmuştur

Kavram

@Ignore

Tanım: Bir test methodunu çalıştırılmaması için kullanılan annotation. Bir test bloğunu silmek veya yorum yapmak yerine başına @Ignore eklemek yeterli olur.

Kavram

Test Suit

Tanım: JUnit'de birden fazla test sınıfından oluşan test grubu. @RunWith ve @SuiteClasses annotation'ları kullanılmakadır

Örnek

Basit Bir Test Suit Sınıfı Örneği

Aşağıda basit bir test suite sınıfı örneği görülmektedir:
import org.junit.runner.*;
import org.junit.runners.*;

@RunWith(Suite.class)
@Suite.SuiteClasses({
  Test1.class,
  Test2.class,
  Test3.class,
  Test4.class
})
public class SimpleTestSuite {
	// bu sınıfın dolu olmasına gerek yoktur
}
Test suite 4 test sınıfından oluşmaktadır ve test suite çalıştırıldığında testler sırasıyla çalıştırılacaktır

Örnek

Basit Bir Test Suite Örneği

Aşağıdaki gibi iki java sınıfı bulunmaktadır:
public class Toplar {
	public int topla(int a, int b){
		return a+b;
	}		
}
public class Carpar {
	public int carp(int a, int b){
		return a*b;
	}	
}
Yukarıdaki iki sınıf için ayrı aşağıdaki gibi iki test sınıfı yapılmıştır:
import static org.junit.Assert.*;
import org.junit.*;
public class ToplaTest {
	Toplar simple;	
	@Before
	public void setUp(){
		simple=new Toplar();
	}	
	@Test
	public void testTopla(){
		int c=simple.topla(1,2);
		assertEquals(3, c);
	}
}
import static org.junit.Assert.*;
import org.junit.*;
public class CarpTest {
	Carpar simple;
	@Before
	public void setUp(){
		simple=new Carpar();
	}	
	@Test
	public void testCarp(){
		int c=simple.carp(1,2);
		assertEquals(2, c);
	}	
}
Yukarıdaki iki testi aynı anda çalıştırabilmek için aşağıdaki gibi bir suite yaratılabilir:
import org.junit.runner.*;
import org.junit.runners.*;

@RunWith(Suite.class)
@Suite.SuiteClasses({
    ToplaTest.class,
    CarpTest.class
})
public class IslemSuit {

}
Yukarıdaki suit, ToplaTest ve CarpTest sınıflarını içermektedir. IslemSuit çalıştırılırsa önce ToplaTest , ardından da CarpTest sınıfları çalışacaktır

Kavram

@Parameters

Tanım: Bir test fonksiyonunu farklı parametreler ile tekrarlamak için kullanılan annotation

Örnek

Basit Bir Parametrik Test Örneği

Aşağıdaki gibi iki sayıyı toplayan bir methodu olan bir sınıfımız olsun:
public class Toplar {	
	public int topla(int a, int b){
		return a+b;
	}		
}
Toplama işlemi sadece bir kere değil, birden fazla sayıda tekrarlanabilir. Bunun için aşağıdaki gibi bir test sınıfı yazılabilir:
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Parameterized.*;

@RunWith(value = Parameterized.class)
public class ToplaTest {
	
	private int number1;
	private int number2;
	private int expected;
	
	public ToplaTest(int number1, int number2, int expected) {
		this.number1=number1;
		this.number2=number2;
		this.expected=expected;
	}
	
	@Parameters(name = "{index}: topla({0}+{1})={2}")
	public static Iterable data1() {
		return Arrays.asList(new Object[][] { 
			{ 2, 2, 4 }, 
			{ 10, 1, 11 }, 
			{ 1, 1, 2 }, 
			{ 100, 1, 101 } 
		});
	}

	@Test
	public void testTopla(){
		Toplar t=new Toplar();
		int c=t.topla(number1,number2);
		assertEquals(expected,c);
	}
}
Her test için gerekli olan parametreler test sınıfın kurucusunda verilmektedir. Toplama örneğinde iki sayı ve toplama sonucu beklediğimiz sayı değerleri bulunmaktadır. Dikkat edilirse @Test ile belirtilen fonksiyon, number1, number2 ve expected şeklinde sınıf değişkenlerini kullanmaktadır. @Parameters ile kullanılacak farklı parametre örnekleri , bir Iterable tipinde verilmiştir. {index}: add({0}+{1})={2} ifadesi ise ekrana basılması sırasında test adımının adı olacaktır. Test çalıştığında aşağıdaki gibi bir çıktı alınacaktır :


[0: topla(2+2)=4]
[1: topla(10+1)=11]
[2: topla(1+1)=2]
[3: topla(100+1)=101]


Aynı örneği kurucu kullanmak yerine değişkenleri public yapıp, @Parameter kullanarak da yapılabilir. Bu şekilde yapılırsa test sınıfı aşağıdaki gibi olur:
import static org.junit.Assert.*;
import java.util.*;
import org.junit.*;
import org.junit.runner.*;
import org.junit.runners.*;
import org.junit.runners.Parameterized.*;

@RunWith(value = Parameterized.class)
public class ToplaTest {
	
	@Parameter
	public int number1;
	
	@Parameter(value = 1)
	public int number2;
	
	@Parameter(value = 2)
	public int expected;

	@Parameters(name = "{index}: topla({0}+{1})={2}")
	public static Iterable data1() {
		return Arrays.asList(new Object[][] { 
			{ 2, 2, 4 }, 
			{ 10, 1, 11 }, 
			{ 1, 1, 2 }, 
			{ 100, 1, 101 } 
		});
	}

	@Test
	public void testTopla(){
		Toplar t=new Toplar();
		int c=t.topla(number1,number2);
		assertEquals(expected,c);
	}
}
Dikkat edilirse kurucuya ihtiyaç yoktur

Veri

assertThat İle Kullanılabilen Özellikler

JUnit , Hamcrest ile matching (eşleme) desteklemektedir. Kullanılabilecek bazı önemli fonksiyonlar aşağıdaki gibidir:
  • is : Örneğin assertThat(d, is(1.3)) , d değerinin 1.3 olmasını test eder
  • not : Örneğin assertThat(d, is(not(1.3))), d değerinin 1.3 olmaması durumunu test eder
  • equalTo : assertThat(str, equalTo("test")), str'in "test" ifadesine eşit olmasını test eder
  • anyOf : assertThat(str, anyOf(is("A"), is("B"), is("C"))) , str ifadesinin A veya B veya C olup olmadığını test eder. Eğer str A,B veya C ise test başarılıdır
  • allOf : assertThat(list, allOf(hasItem("A"), hasItem("B"))), list'de hem A hem de B var ise test başarılıdır
  • any : assertThat(obj, is(any(String.class))) , obj nesnesi bir String ise test başarılıdır
  • instanceOf : assertThat(obj, is(instanceOf(String.class))) , obj nesnesi bir String ise test başarılıdır
  • nullValue : assertThat(obj, is(nullValue())), obj nesnesi null ise test başarılıdır
  • notNullValue : assertThat(obj, is(notNullValue())); , obj nesnesi null değilse test başarılıdır
  • sameInstance : assertThat(obj, is(sameInstance(other))) , obj ile other aynı instance ise test başarılıdır
  • containsString : assertThat(obj, containsString("Ali")), obj içinde Ali geçiyor ise test başarılıdır
  • startsWith : assertThat(obj, startsWith("my")), obj my ile başlıyorsa test başarılıdır
  • endsWith : assertThat(obj, endsWith("Ali")), obj String ve Ali ile bitiyor ise test başarılıdır
  • hasItem : assertThat(list, hasItem("two")) , bir liste içinde "two" olan bir String maddesi var mı test eder
  • hasItems : assertThat(list, hasItems("one", "two")), bir liste içinde one veya two varsa test başarılıdır


Kavram

Assume

Tanım: JUnit'de, bir koşulun gerçekleşmemesi durumunda testi kesmek (örneğin test için gerekli ön koşulların oluşmaması durumu) için kullanılan sınıf. assumeThat, assumeTrue gibi farklı fonksiyonları bulunmaktadır.

Örnek

Assume İle Sadece Windows İçin Çalışacak Test Örneği

Aşağıdaki örnekteki test kodu sadece Windows işletim sistemi olan ortamda çalışacaktır:
@Test
public void windowsTest() {
  assumeTrue(System.getProperty("os.name").toLowerCase().contains("win"));
  // test kesilir, kosul gerceklesmedi
}

Kavram

Theory

Tanım: Farklı parametre ve bu parametrelerle yapılabilecek farklı olasılıkları test etmeyi sağlayan sınıf ve bu sınıf. heory kullanılacak test sınıfının başına @RunWith(Theories.class) eklenir. @DataPoint ile parametreler, @Theory ile de test method'u tanımlanır.

Örnek

İki Sayıyı Toplayan Basit Bir Theory Örneği

Aşğaıdaki gibi bir sınıfımız olsun:
public class Toplar {   
    public int topla(int a, int b){
        return a+b;
    }       
}
Bu sınıfdaki topla methodu için Theory sınıfı aşağıdaki gibidir:
import org.junit.experimental.theories.*;
import org.junit.runner.*;
import static org.junit.Assert.*;
@RunWith(Theories.class)
public class TheoryTest {	
	@DataPoints public static int[] first = new int[] {1, 2};
	@DataPoints public static int[] second = new int[] {3, 4};
	@Theory
    public void testTopla(int a, int b) {
		System.out.println(a+"+"+b);
		assertEquals(a+b, (new Toplar()).topla(a, b));
    }	
}
DataPoints ile kullanılabilecek veriler verilmektedir. Verilen iki sayının + ile toplaı ile toplam fonksiyonudan gelen değerlerin tutması gerekiyor. Test çalıştırıldığında tüm olasılıklar ekrana basılmıştır:


1+1
1+2
1+3
1+4
2+1
2+2
2+3
2+4
3+1
3+2
3+3
3+4
4+1
4+2
4+3
4+4

Kavram

Category

Tanım: Junit'de test method'larının ve sınıflarınının kategorilere ayırmak için kullanılan sınıf ve bu sınıfın annotation'ı. @Category(X.class) ile bir test methodunun X.class kategorisine ait olduğu belirtilmiş olur. Bir test suitte @RunWith(Categories.class) @IncludeCategory(X.class) ifadeleri ile, sadece X kategorisindeki testlerin çalışması sağlanabilir. Benzer şekilde @ExcludeCategory(X.class) ile X hariç diğer kategorilerin çalışması sağlanabilir.

İpucu

Test Methodlarının Sıralı Çalıştırılması

Bir JUnit sınıfında , sıralama için @FixMethodOrder kullanılabilir.
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class ExternalSubscriptionManageTest {
	@Test
	public void test2(){..}
	@Test
	public void test3(){..}
	@Test
	public void test1(){..}
}
Yukarıdaki örnekte method isimlerine göre test method'ları sırayla çağrılmaktadır. Önce test1 , sonra test2 ve en son test3 çalıştırılacaktır

Kavram

Mockito

Tanım: Java'de birim testlerinde mock nesnelerin yaratmanızı sağlayan kütüphane

Örnek

JUnit 5 ile Basit Bir Test Örneği

JUnit 5 ile basit bir test yapabilmek için aşağıdaki bağımlılığı eklemek gerekir:
<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-engine</artifactId>
	<version>5.4.0-M1</version>
	<scope>test</scope>
</dependency>
Maven kullanmıyorsanız gerekli jar'ları eklemeniz gerekir. 5.4 versiyonu henüz geliştirme aşamasındadır. Bir önceki versiyon da kullanılabilir. Test edilecek aşağıdaki gibi bir sınıf yapalım:
public class Hello {
	public static String hello(String name) {	
		return "hello "+name;						
	}	
}
Test kodu aşağıdaki gibidir:
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class HelloTest {
	@Test
	public void helloTest() {	
		String result=Hello.hello("test");
		assertEquals("hello test", result);		
	}	
}
Eğer dönen metin "hello test" ise sonuç test başarılı olacaktır.

Örnek

JUnit 5 ile TemporaryFolder Kullanımı

JUnit 5'de rule desteği kaldırılmıştır. TemporaryFolder gibi bazı ön tanımlı rule'lar da JUnit 5 kütüphanesinde artık bulunmamaktadır. Ancak 5.4.2 sürümünden sonra @TempDir şeklinde Temporary Folder desteği gelmiştir. 5.4.2 öncesi TemporaryFolder işlevini sağlamak için TemporaryFolder uzantısı (extention) yaratmanız gerekir. Veya junit-extensions projesini kullanabilirsiniz. Bu github.com/glytching/junit-extensions ve glytching.github.io/junit-extensions/index bağlantılarına bakabilirsiniz.
Öncelikle projeye bağımlılıkları aşağıdaki gibi ekleyebiliriz:
<dependency>
	<groupId>org.junit.jupiter</groupId>
	<artifactId>junit-jupiter-engine</artifactId>
	<version>5.4.0-M1</version>
	<scope>test</scope>
</dependency>
<dependency>
	<groupId>io.github.glytching</groupId>
	<artifactId>junit-extensions</artifactId>
	<version>2.3.0</version>
	<scope>test</scope>
</dependency>
Öncelikle test edilecek bir sınıf yazalım. Bu sınıf bir properties dosyasını yükleyen bir sınıf olsun:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesLoader {
	private Properties properties=null;
	public void load(String path) 
			throws FileNotFoundException, IOException {		
		properties=new Properties();
		try(InputStream is=new FileInputStream(path)){
			properties.load(is);
		}		
	}	
	public String getProperty(String key) {
		return properties.getProperty(key);
	}	
}
Bu sınıfı test etmek için TemporaryFolderExtension'ı kullanan bir test sınıfı aşağıdaki gibi yaratılabilir:
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import io.github.glytching.junit.extension.folder.TemporaryFolder;
import io.github.glytching.junit.extension.folder.TemporaryFolderExtension;
@ExtendWith(TemporaryFolderExtension.class)
public class PropertiesLoaderTest {
   private static File file;
    @BeforeAll
    public static void prepare(TemporaryFolder givenTemporaryFolder) throws IOException {   	
		file = givenTemporaryFolder.createFile("test.properties");
		
		Properties properties=new Properties();
		properties.put("test", "testvalue");
		
		try(OutputStream os =new FileOutputStream(file)){
			properties.store(os,"test properties");
		}		
    }
	@Test
	@ExtendWith(TemporaryFolderExtension.class)
	public void loadTest() throws IOException {
		
		PropertiesLoader loader=new PropertiesLoader();
		loader.load(file.getAbsolutePath());
		
		assertEquals("testvalue", loader.getProperty("test"));
	}
}
Sınıfın en üstünde @ExtendWith(TemporaryFolderExtension.class) ile TemporaryFolderExtension'ı kullanacağımız belirtiyoruz. @BeforeAll ile tanımlanan yöntem ile TemporaryFolder'ı alıyoruz ve bir properties dosyasını yaratıyoruz. loadTest() yönteminde ise asıl test edeceğimiz PropertiesLoader sınıfını yaratıyoruz ve verilen path'deki properties dosyasını yükletiyoruz. Eğer test değeri testvalue ise PropertiesLoader başarılı bir şekilde çalışmış demektir.
JUnit 5, 5.4.2 sonrası için herhangi bir extention kütüphanesi kullanmadan "@TempDir Path path" şeklinde test yöntemlerine aktarılabilirsiniz:
@Test
public void createFileTest(@TempDir Path tempDir) {
	
	String testFilePath=tempDir.toString()+File.separator+"test.txt";
	
	try {
		Files.createFile(Paths.get(testFilePath));
	} catch (IOException e) {
		fail(e);
	}
	
	//...
}

İpucu

Rulet Çemberi Birim Testi

Rulet Çemberi Seçimi algoritmasi olasılığa dayanan bir algoritma olduğu için birim testini yapmak zor. Örneğin şuradaki algoritmayı test etmek isteyelim : Rulet Çemberi Seçimi Algoritması
Junit 5 ile aşağıdaki gibi bir test yapılabilir :
@RepeatedTest(100)
public void testRouletteWheelSelector() {
	
	int[] values=new int[]{0,100};
	
	int index = RouletteWheelSelector.select(values);
	
	assertEquals(1, index);
			
}
Bu test 100 kere tekrarlandığında hep başarılı olmalıdır. Çünkü ile değer 0 olasılıktır ve hep ikinci seçilecektir.
Olasılıkta örnekler ne kadar fazla ise sonuç olasılık değerlerine yaklaşır. Bir yazı turayı bir milyon kez atarsanız yaklaşık 500 bin kez tura ve yazı gelir. Yüz milyona çıkarırsanız daha da değerler yaklaşır birbirine. Bunu şu şekilde kullanabiliriz :
static int index1Count=0;
static int index2Count=0;
@BeforeAll
public static void init() {
	index1Count=0;
	index2Count=0;
}
@RepeatedTest(10000)
public void testRouletteWheelSelector50Percent() {
	
	int[] values=new int[]{50,50};
	
	int index = RouletteWheelSelector.select(values);
	
	if(index==0) {
		index1Count++;
	}if(index==1) {
		index2Count++;
	}			
}
@AfterAll
public static void beforeAll() {
	
	System.out.println(index1Count+":"+index2Count);
}

Değerler %50 ve %50 verilmesinden dolayı çıkan sonuçlar birbirine yakın olmalıdır. Örneğin 5100 - 4900 gibi değerler çıkacaktır. Yüz bin kez de yapılabilir test. Tabi burada çıkan sonucu insan gözüyle değerlendirdik. Halbuki bir hata payı verip kod ile test etmeliydik.



Bu Sayfayı Paylaş:

İletişim Bilgileri

Takip Et

Her Hakkı Saklıdır. Bu sitede yayınlanan tüm bilgi ve fikirlerin kullanımından fibiler.com sorumlu değildir. Bu sitede üretilmiş , derlenmiş içerikleri, fibiler.com'u kaynak göstermek koşuluyla kendi sitenizde kullanılabilirsiniz. Ancak telif hakkı olan içeriklerin hakları sahiplerine aittir