JUnit'i neden test etmek için kullanmalısınız?


131

Belki sorum acemi bir sorudur, ancak kullanacağım koşulları gerçekten anlayamıyorum ?

İster basit ister daha büyük uygulamalar yazayım, bunları System.outifadelerle test ediyorum ve bana oldukça kolay geliyor.

Hala aynı yöntemleri çağırmamız, geri döndüklerini kontrol etmemiz ve sonra her şeye ek açıklama getirmemiz gerekiyorsa, projede JUnit ile test sınıfları, gereksiz klasörler oluşturalım?

Neden bir sınıf yazıp bir kerede test System.outetmiyorsunuz ama Test sınıfları oluşturmuyorsunuz?

PS. Henüz yeni öğrendiğim büyük projelerde hiç çalışmadım.

Öyleyse amaç nedir?



7
Programınızda herhangi bir şeyi her değiştirdiğinizde, çıktının manuel olarak incelenmesiyle ilgili tüm önceki çalışmalarınızın geçersiz kılındığının ve bunları baştan yeniden yapmanız gerektiğinin farkında mısınız?
Thorbjørn Ravn Andersen

Sadece "test etmek" değil, aynı zamanda "akıllıca test etmek" de çok önemlidir. : İşte bunun güzel bir örneğidir wp.me/prMeE-11
akcasoy

Yanıtlar:


139

Bu test değil, bu "çıktıya manuel olarak bakmak" (bizde LMAO olarak bilinir). Daha resmi olarak "anormal çıktıyı manuel olarak aramak" (LMFAO) olarak bilinir. (Aşağıdaki nota bakın)

Kodu her değiştirdiğinizde, bu değişikliklerden etkilenen tüm kodlar için uygulamayı ve LMFAO'yu çalıştırmanız gerekir. Küçük projelerde bile bu sorunludur ve hataya açıktır.

Şimdi bir kod değişikliği yaptığınızda 50k, 250k, 1m LOC ve LMFAO'ya kadar ölçeklendirin. Sadece tatsız değil, aynı zamanda imkansız: girdilerin, çıktıların, bayrakların, koşulların kombinasyonlarını büyüttünüz ve tüm olası dalları uygulamak zor.

Daha da kötüsü LMFAO, web uygulamasının sayfalarını ziyaret etmek, raporları çalıştırmak, düzinelerce dosya ve makineye milyonlarca günlük satırını incelemek, oluşturulan ve iletilen e-postaları okumak, metin mesajlarını kontrol etmek, bir robotun yolunu kontrol etmek, bir şişe doldurmak anlamına gelebilir. soda, yüzlerce web hizmetinden veri toplamak, bir finansal işlemin denetim izini kontrol etmek ... fikri anladınız. "Çıktı", birkaç satırlık metin anlamına gelmez, "çıktı" toplu sistem davranışı anlamına gelir.

Son olarak, birim ve davranış testleri sistem davranışını tanımlar . Testler, sürekli bir bütünleştirme sunucusu tarafından çalıştırılabilir ve doğruluk açısından kontrol edilebilir. Tabii ki de olabilir System.out, ancak CI sunucusu bunlardan birinin yanlış olup olmadığını bilemeyecek - ve eğer öyleyse, bunlar birim testler ve siz de bir çerçeve kullanabilirsiniz.

Ne kadar iyi olduğumuzu düşünürsek düşünelim, insanlar iyi birim test çerçeveleri veya CI sunucuları değildir.


Not: LMAO edilir fakat içinde, test çok sınırlı anlamda. Tüm bir proje boyunca veya bir sürecin parçası olarak anlamlı bir şekilde tekrarlanamaz. Bir REPL'de aşamalı olarak geliştirmeye benzer, ancak bu artımlı testleri asla resmileştirmez.


3
Tamamen ve tamamen yanlış olan ilk cümle için -1.
Michael Borgwardt

50

Bir programın davranışının doğruluğunu onaylamak için testler yazıyoruz.

Gözlerinizi kullanarak çıktı ifadelerinin içeriğini inceleyerek bir programın davranışının doğruluğunu onaylamak bir kılavuzdur veya daha spesifik olarak görsel bir süreçtir.

Bunu tartışabilirsin

görsel inceleme işe yarıyor , bu senaryolar için kodun yapması gerekeni yaptığını kontrol ediyorum ve doğru olduğunu anladığımda gitmemiz iyi olur.

Şimdi ilk olarak, kodun doğru çalışıp çalışmadığıyla ilgilenmeniz harika. Bu iyi birşey. Eğrinin önündesin! Ne yazık ki, bununla ilgili bir yaklaşım olarak sorunlar var.

Görsel incelemeyle ilgili ilk sorun, kodunuzun doğruluğunu bir daha asla kontrol edemeyeceğiniz için kötü bir kaynak kazası olmanızdır.

İkinci sorun, kullanılan göz çiftinin, göz sahibinin beyniyle sıkı bir şekilde birleşmesidir. Kodun yazarı da görsel inceleme sürecinde kullanılan gözlere sahipse, doğruluğu doğrulama süreci, görsel denetçinin beyninde içselleştirilen program hakkındaki bilgiye bağımlıdır.

Yeni bir çift gözün içeri girip kodun doğruluğunu doğrulaması zordur çünkü bunlar orijinal kodlayıcının beyniyle ortaklaşa çalışmazlar. İkinci göz çiftinin sahibi, söz konusu kodu tam olarak anlamak için kodun orijinal yazarıyla görüşmek zorunda kalacaktır . Bilgiyi paylaşmanın bir yolu olarak konuşma, herkesin bildiği gibi güvenilmezdir. Orijinal Kodlayıcı yeni çift gözler için mevcut değilse tartışmalı bir nokta. Bu durumda, yeni göz çiftinin orijinal kodu okuması gerekir.

Başkalarının birim testleri tarafından kapsanmayan kodunu okumak, ilişkili birim testleri olan kodu okumaktan daha zordur. En iyi ihtimalle diğer insanların kodunu okumak zor bir iştir, en kötü ihtimalle bu, yazılım mühendisliğindeki en ağır görevdir. İşverenlerin boş iş ilanlarını ilan ederken, bir projenin yeşil alan (veya yepyeni) olduğunu vurgulamasının bir nedeni vardır. Sıfırdan kod yazmak, mevcut kodu değiştirmekten daha kolaydır ve bu nedenle reklamı yapılan işin potansiyel çalışanlar için daha çekici görünmesini sağlar.

Birim testi ile kodu bileşen parçalarına ayırıyoruz. Her bileşen için daha sonra programın nasıl davranması gerektiğini belirterek durağımızı koyarız . Her birim testi, programın bu bölümünün belirli bir senaryoda nasıl davranması gerektiğine dair bir hikaye anlatır. Her birim testi, müşteri kodunun bakış açısından ne olması gerektiğini açıklayan bir sözleşmedeki bir madde gibidir.

Bu daha sonra gözlerin yeni çifti sahip olduğu anlamına gelir iki ipliklerini canlı ve doğru söz konusu kod belgelere.

İlk önce kodun kendisine, uygulamaya, kodun nasıl yapıldığına ; ikinci olarak, orijinal kodlayıcının, bu kodun nasıl davranması gerektiğinin hikayesini anlatan bir dizi resmi ifadede tanımladığı tüm bilgilere sahipler .

Birim testleri, orijinal yazarın sınıfı uygularken sahip olduğu bilgileri yakalar ve resmen açıklar. Bir müşteri tarafından kullanıldığında o sınıfın nasıl davrandığına dair bir açıklama sağlarlar.

Bunu yapmanın faydasını sorgulamakta haklısınız çünkü işe yaramaz, söz konusu kodun tamamını kapsamayan, eskimiş veya geçerliliğini yitirmiş birim testleri yazmak mümkündür. Bilgili, vicdanlı bir yazarın çalışma zamanında kodlarının çıktı ifadelerini görsel olarak inceleyen birim testlerinin yalnızca taklit etmesini değil, aynı zamanda sürecini geliştirmesini nasıl sağlayabiliriz? Önce birim testini yazın, ardından bu testi geçmesi için kodu yazın. Bitirdiğinizde, bırakın bilgisayarlar testleri çalıştırsınlar, hızlıdırlar ve işe ideal olarak uygun oldukları tekrarlayan görevleri yerine getirmede harikadırlar.

Test ettikleri koda her dokunduğunuzda bunları gözden geçirerek test kalitesini sağlayın ve her derleme için testleri çalıştırın. Bir test başarısız olursa hemen düzeltin.

Projenin her derlemesini yaptığımızda testler çalıştırılacak şekilde çalıştırma sürecini otomatikleştiriyoruz. Ayrıca, testler tarafından kapsanan ve uygulanan kod yüzdesini ayrıntılarıyla açıklayan kod kapsamı raporlarının oluşturulmasını otomatik hale getiriyoruz. Yüksek yüzdeler için çalışıyoruz. Bazı şirketler, koddaki davranıştaki herhangi bir değişikliği açıklamak için yeterli birim testleri yazılmamışsa, kod değişikliklerinin kaynak kod kontrolüne eklenmesini önleyecektir. Tipik olarak ikinci bir çift göz, değişikliklerin yazarı ile birlikte kod değişikliklerini gözden geçirecektir. İncelemeyi yapan kişi, değişikliklerin anlaşılır olmasını ve testler tarafından yeterince kapsanmasını sağlamak için değişikliklerden geçecektir. Dolayısıyla inceleme süreci manueldir, ancak testler (birim ve entegrasyon testleri ve muhtemelen kullanıcı kabul testleri) bu manuel inceleme sürecini geçtiğinde, otomatik oluşturma sürecinin bir parçası haline gelir. Bunlar, her değişiklik kontrol edildiğinde çalıştırılır. sunucu, bu görevi, oluşturma sürecinin bir parçası olarak gerçekleştirir.

Otomatik olarak çalıştırılan testler, kodun davranışının bütünlüğünü korur ve kod tabanında gelecekte yapılacak değişikliklerin kodu bozmasını önlemeye yardımcı olur .

Son olarak, testler sağlamak, kodu agresif bir şekilde yeniden faktörlendirmenize olanak tanır çünkü değişikliklerinizin mevcut testleri bozmayacağını bilerek büyük kod iyileştirmelerini güvenli hale getirebilirsiniz.

Test Odaklı Geliştirme için bir uyarı var ve bu, test edilebilir hale getirmek için bir gözle kod yazmanız gerektiğidir. Bu, arayüzlere kodlamayı ve işbirliği yapan nesneleri örneklemek için Bağımlılık Ekleme gibi teknikleri kullanmayı içerir. TDD'yi çok iyi tanımlayan Kent Beck'in çalışmasına göz atın . Yukarı bak arayüzleri kodlama ve çalışma


13

System.out gibi bir şey kullanarak test ettiğinizde, yalnızca olası kullanım durumlarının küçük bir alt kümesini test edersiniz. Bu, neredeyse sonsuz sayıda farklı girdiyi kabul edebilecek sistemlerle uğraşırken çok kapsamlı değildir.

Birim testleri, çok büyük ve çeşitli farklı veri girdileri kullanarak uygulamanızda hızlı bir şekilde testler yapmanıza olanak sağlamak için tasarlanmıştır. Ek olarak, en iyi birim testleri, geçerli kabul edilenin tam kenarında yer alan veri girişleri gibi sınır durumlarını da hesaba katar.

Bir insanın tüm bu farklı girdileri test etmesi haftalar sürebilirken, bir makine için dakikalar alabilir.

Şöyle düşünün: Ayrıca statik olacak bir şeyi "test etmiyorsunuz". Uygulamanız büyük olasılıkla sürekli değişikliklerden geçiyor. Bu nedenle, bu birim testleri, derleme veya dağıtım döngüsünün farklı noktalarında çalışacak şekilde tasarlanmıştır. Belki de en büyük avantaj şudur:

Kodunuzdaki bir şeyi bozarsanız, bunu hemen şimdi öğreneceksiniz , konuşlandırdıktan sonra değil, bir QA testçisi bir hata yakaladığında, müşterileriniz iptal ettiğinde değil. Ayrıca, söz konusu kodun parçasını bozan şeyin büyük olasılıkla son derlemenizden sonra meydana geldiği açık olduğundan , arızayı hemen düzeltme şansınız daha yüksektir. Böylece, sorunu çözmek için gereken araştırma çalışması miktarı büyük ölçüde azaltılır.


9

Başka bir System.out ekledim YAPAMAZ:

  • Her test senaryosunu bağımsız yapın (Önemli)

    JUnit bunu yapabilir: her seferinde yeni test senaryosu oluşturulur ve @Beforeçağrılır.

  • Test kodunu kaynaktan ayırın

    JUnit yapabilir.

  • CI ile entegrasyon

    JUnit bunu Ant ve Maven ile yapabilir.

  • Test durumlarını kolayca düzenleyin ve birleştirin

    JUnit @Ignorepaketi yapabilir ve test edebilir .

  • Sonucu kontrol etmek kolay

    JUnit birçok Assert yöntemi sunar ( assertEquals, assertSame...)

  • Mock ve stub, test modülüne odaklanmanızı sağlar.

    JUnit şunları yapabilir: Mock ve stub kullanmak, doğru fikstürü kurmanızı ve test modülü mantığına odaklanmanızı sağlar.


9

Birim testleri, kodun amaçlandığı gibi çalışmasını sağlar. Ayrıca, bir hatayı düzeltmek için yeni işlevler oluşturmak için kodu daha sonra değiştirmeniz gerekmesi durumunda, kodun amaçlandığı gibi çalışmasını sağlamaya da çok yardımcı olurlar. Kodunuzun test kapsamının yüksek olması, çok sayıda manuel test yapmak zorunda kalmadan özellikleri geliştirmeye devam etmenizi sağlar.

Manuel yaklaşımınız System.outiyidir, ancak en iyisi değildir. Bu, gerçekleştirdiğiniz tek seferlik testtir. Gerçek dünyada, gereksinimler değişmeye devam eder ve çoğu zaman mevcut işlevlere ve sınıflara birçok değişiklik yaparsınız. Öyleyse… önceden yazılmış kod parçasını her test ettiğinizde değil.

JUnit'te olduğu gibi bazı daha gelişmiş özellikler de vardır.

İfadeleri onaylayın

JUnit, belirli koşulları test etmek için yöntemler sağlar, bu yöntemler tipik olarak iddialarla başlar ve hata mesajını, beklenen ve gerçek sonucu belirlemenizi sağlar.

Bu yöntemlerden bazıları

  1. fail([message])- Testin başarısız olmasına izin verir. Kodun belirli bir kısmına ulaşılıp ulaşılmadığını kontrol etmek için kullanılabilir. Veya test kodu uygulanmadan önce başarısız teste sahip olmak.
  2. assertTrue(true)/ assertTrue(false)- Her zaman doğru / yanlış olacaktır. Test henüz uygulanmadıysa, bir test sonucunu önceden tanımlamak için kullanılabilir.
  3. assertTrue([message,] condition) - Boole değerinin condition değerinin doğru olup .
  4. assertEquals([message,] expected, actual)- İki değerin eşit olup olmadığını test eder ( equalsuygulanıyorsa yönteme göre , aksi takdirde ==referans karşılaştırması kullanılır). Not: Diziler için, kontrol edilen, içerik değil referanstır.assertArrayEquals([message,] expected, actual) için .
  5. assertEquals([message,] expected, actual, delta) - İki kayan değerin veya çift değerin birbirinden belirli bir mesafede olup olmadığını test eder. delta Değer .
  6. assertNull([message,] object) - Nesnenin boş olup olmadığını kontrol eder

ve bunun gibi. Buradaki tüm örnekler için tam Javadoc'a bakın .

Suites

Test paketleri ile, bir anlamda birden çok test sınıfını tek bir birimde birleştirebilir, böylece hepsini aynı anda yürütebilirsiniz. Basit bir örnek, test sınıflarını MyClassTestve MySecondClassTesttek bir Suite adı verilen AllTests:

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

@RunWith(Suite.class)
@SuiteClasses({ MyClassTest.class, MySecondClassTest.class })
public class AllTests { } 

6

JUnit'in ana avantajı, çıktılarınızı manuel olarak kontrol etmek zorunda kalmadan otomatikleştirilmesidir. Yazdığınız her test sisteminizde kalır. Bu, beklenmedik bir yan etkiye sahip bir değişiklik yaparsanız, her değişiklikten sonra her şeyi manuel olarak test etmeyi hatırlamanız yerine, testinizin onu yakalayıp başarısız olacağı anlamına gelir.


4

JUnit, Java Programlama Dili için bir birim test çerçevesidir. Test güdümlü geliştirmede önemlidir ve topluca xUnit olarak bilinen birim testi çerçeveleri ailesinden biridir.

JUnit, önce test edilebilecek ve daha sonra uygulanabilecek bir kod parçası için test verilerini ayarlamaya vurgu yapan "önce test sonra kodlama" fikrini teşvik eder. Bu yaklaşım, "biraz test edin, biraz kodlayın, biraz test edin, biraz kodlayın ..." gibidir. Bu, programcı verimliliğini ve program kodunun kararlılığını artırarak programcı stresini ve hata ayıklamaya harcanan zamanı azaltır.

Özellikler JUnit, testleri yazmak ve çalıştırmak için kullanılan açık kaynaklı bir çerçevedir.

Test yöntemlerini tanımlamak için Ek Açıklama sağlar.

Beklenen sonuçları test etmek için Onaylar sağlar.

Testleri çalıştırmak için Test çalıştırıcıları sağlar.

JUnit testleri, kaliteyi artıran daha hızlı kod yazmanıza olanak tanır

JUnit zarif ve basittir. Daha az karmaşıktır ve daha az zaman alır.

JUnit testleri otomatik olarak çalıştırılabilir ve kendi sonuçlarını kontrol eder ve anında geri bildirim sağlar. Test sonuçları raporunu manuel olarak taramanıza gerek yoktur.

JUnit testleri, test senaryolarını ve hatta diğer test süitlerini içeren test paketleri halinde organize edilebilir.

Junit, testin ilerleyişini yeşil olan bir çubukta, test iyi giderse gösterir ve bir test başarısız olduğunda kırmızıya döner.


2

JUnit'in neden gerekli olduğuna dair biraz farklı bakış açım var.

Aslında tüm test durumlarını kendiniz yazabilirsiniz, ancak bu külfetli bir iştir. İşte sorunlar:

  1. Bunun yerine 0 veya -1 veya hata mesajı System.outekleyip if(value1.equals(value2))döndürebiliriz. Bu durumda, tüm bu yöntemleri çalıştıran ve sonuçları kontrol eden ve hangi test durumlarının başarısız olduğunu ve hangilerinin geçtiğini tutan bir "ana" test sınıfına ihtiyacımız var.

  2. Daha fazla test eklemek isterseniz, onları da bu "ana" test sınıfına eklemeniz gerekir. Mevcut kodda değişiklikler. Test sınıflarından test senaryolarını otomatik olarak tespit etmek istiyorsanız, yansıtma kullanmanız gerekir.

  3. Tüm testleriniz ve testleri çalıştırmak için ana sınıfınız tutulma tarafından algılanmaz ve bu testleri çalıştırmak için özel hata ayıklama / çalıştırma yapılandırmaları yazmanız gerekir. Yine de bu oldukça yeşil / kırmızı renkli çıktıları görmüyorsunuz.

İşte JUnit'in yaptığı şey:

  1. Koşullardan assertXXX()yararlı hata mesajlarını yazdırmak ve sonuçları "ana" sınıfa iletmek için yararlı yöntemlere sahiptir.

  2. "main" sınıfa JUnit tarafından sağlanan runner denir, bu nedenle herhangi bir şey yazmak zorunda değiliz. Ve test yöntemlerini yansıtarak otomatik olarak algılar. @TestEk açıklamalı yeni testler eklerseniz, bunlar otomatik olarak algılanır.

  3. JUnit, tutulma entegrasyonuna ve maven / gradle entegrasyonuna da sahiptir, bu nedenle testleri çalıştırmak kolaydır ve özel çalıştırma konfigürasyonları yazmak zorunda kalmazsınız.

JUnit konusunda uzman değilim, bu yüzden şu an anladığım şey, gelecekte daha fazlasını ekleyecektir.


Sanırım ilk bölümde, birim testini system.out.println ifadelerinden biraz daha iyi hale getirmek için JUnit orada olmasaydı ne yapacağımızı yazmıştınız. JUnit, bazı programcıların bu tür girişimlerinin sonucudur ve bu otomasyonu gerçekleştirmek için ayrı bir test çerçevesi yazma ihtiyacı hissettiler, dolayısıyla JUnit doğmuş olabilir.
Saurabh Patil

1

Test çerçevesi kullanmadan herhangi bir test senaryosu yazamazsınız, aksi takdirde test senaryolarınızın hakkını vermek için test çerçevenizi yazmanız gerekecektir. İşte TestNG çerçevesini kullanabileceğiniz dışında JUnit Framework hakkında bazı bilgiler.

Junit nedir?

Junit, Java Programlama Dili ile birlikte yaygın olarak kullanılan test çerçevesidir. Bu otomasyon çerçevesini hem birim testi hem de UI testi için kullanabilirsiniz.Kodumuzun yürütme akışını farklı Açıklamalar ile tanımlamamıza yardımcı olur. Junit, test senaryolarının üretkenliğini ve kodun kararlılığını artırmamıza yardımcı olan "önce test ve ardından kodlama" fikri üzerine kurulmuştur.

Junit Testinin Önemli Özellikleri -

  1. Kullanıcıların etkin bir şekilde test senaryoları yazmasına ve çalıştırmasına olanak tanıyan açık kaynaklı test çerçevesidir.
  2. Test yöntemlerini tanımlamak için çeşitli türlerde ek açıklamalar sağlar.
  3. Test senaryosu yürütmenin sonuçlarını doğrulamak için farklı Onay Türleri sağlar.
  4. Ayrıca, testleri etkili bir şekilde yürütmek için test koşucuları sağlar.
  5. Çok basittir ve bu nedenle zaman kazandırır.
  6. Test senaryolarınızı test kıyafetleri şeklinde organize etmenin yollarını sağlar.
  7. Basit ve şık bir şekilde test senaryosu sonuçlarını verir.
  8. JUnit'i Eclipse, Android Studio, Maven & Ant, Gradle ve Jenkins ile entegre edebilirsiniz

0

JUNIT, genellikle java geliştiricisi tarafından kabul edilen yöntemdir. İşleve benzer beklenen girdiyi sağlayabildikleri ve buna göre yazılı kodun mükemmel bir şekilde yazıldığına karar verebilecekleri durumlarda veya test senaryosu başarısız olursa, farklı yaklaşımın da uygulanması gerekebilir. JUNIT, geliştirme sürecini hızlandıracak ve fonksiyondaki 0 ​​hatayı garanti altına alacaktır.


0

HAZİRAN: GÖZLEMLE VE AYARLA

İşte JUNIT'e bakış açım.

JUNIT,
1) Bir sisteme yeni bir birim eklendiğinde bir sistem davranışını gözlemlemek için kullanılabilir .
2) Sistemdeki "yeni" birimi karşılayacak şekilde sistemde ayar yapın.
Ne? Kesinlikle.

Örneğin gerçek hayat.

Yakınınız üniversite yurt odanızı ziyaret ettiğinde,
1) Daha sorumlu gibi davranacaksınız.
2) Sandalyede değil ayakkabı rafında, sandalyede değil dolapta bulunan ayakkabılar gibi her şeyi olması gereken yerde tutacaksınız.
3) Tüm kaçak mallardan kurtulacaksınız.
4) Sahip olduğunuz her cihazda temizlemeye başlayacaksınız.

Programlama açısından

Sistem: Kodunuz
BİRİM: yeni işlevsellik.
JUNIT çerçevesi JAVA dili için kullanıldığından JUNIT = JAVA UNIT (Olabilir).

Zaten kurşun geçirmez bir kodunuz olduğunu, ancak yeni bir gereksinim geldiğini ve kodunuza yeni gereksinimi eklemeniz gerektiğini varsayalım. Bu yeni gereksinim, bazı girdiler (test senaryosu) için kodunuzu bozabilir.

Bu değişikliği uyarlamanın kolay yolu, birim testini (JUNIT) kullanmaktır.
Bunun için kod tabanınızı oluştururken kodunuz için birden fazla test senaryosu yazmalısınız. Ve yeni bir gereksinim geldiğinde, herhangi bir test senaryosunun başarısız olup olmadığını görmek için tüm test senaryolarını çalıştırmanız yeterlidir. Hayır ise, o zaman bir BadA ** sanatçısısınız ve yeni kodu dağıtmaya hazırsınız.
Test durumlarından herhangi biri başarısız olursa, kodunuzu değiştirirsiniz ve yeşil durumu elde edene kadar test olaylarını tekrar çalıştırırsınız.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.