Berk Akademi
Ana Sayfa
ÖZEL KODLAMA DERSLERİ
Yazılım Özel Ders
Tüm birebir programlara genel bakış
Python Yazılım Kursu
Sıfırdan ileri seviyeye birebir Python
Java Yazılım Kursu
OOP odaklı birebir Java eğitimi
AP Computer Science Principles
AP CSP sınav hazırlığı
GRUP DERSLERİ
Python & Django Masterclass
SINIRLI KONTENJAN
Java & Spring Boot Masterclass
SINIRLI KONTENJAN
C# .NET Masterclass
SINIRLI KONTENJAN
VİDEO DERSLER
Sıfırdan Temel Python Kursu
Kendi Hızında Öğren
ÜCRETSİZ
Seviye Testi
Ücretsiz — Python, Java, algoritma seviye testleri
Kariyerini Keşfet
Sertifika Doğrula
Belge numarası ve soyad ile doğrulama

C#'ta xUnit ile Birim Test Yazmanın Temel Mantığı

Yazar: Berk Keskin 29.08.2026 ~12 dk okuma 1 Okunma
csharp-xunit-ile-birim-test-yazma-mantigi

C#'ta xUnit ile birim test yazmak, bir metodun veya sınıfın belirli girdiler karşısında beklenen çıktıyı üretip üretmediğini otomatik ve tekrarlanabilir biçimde doğrulamak anlamına gelir. Bu mantığın temelinde [Fact] ve [Theory] gibi öznitelikler, test sınıfları ve Assert metotları yer alır; xUnit bu yapıları kullanarak kodun her değişiklikten sonra hâlâ doğru çalıştığını hızlıca kanıtlamanı sağlar. İlerleyen bölümlerde bu yapı taşlarını tek tek, gerçek kod örnekleriyle inceleyeceğiz.

Birim Test Nedir ve Neden Yazılır?

Birim test (unit test), bir programın en küçük anlamlı parçasını -genellikle tek bir metodu veya fonksiyonu- diğer bileşenlerden izole ederek test etme pratiğidir. Amaç, o küçük parçanın belirli bir girdi karşısında her zaman beklenen çıktıyı üretip üretmediğini kanıtlamaktır. Bir metodu izole test etmek, o metodun bağlı olduğu veritabanı, dosya sistemi veya dış servis gibi unsurlardan bağımsız çalışmasını sağlamak demektir; böylece testin başarısız olması, gerçekten o metodun mantığındaki bir hatayı işaret eder.

Birim testlerin önemi, yazılımın büyüklüğü arttıkça daha da belirginleşir. Bir projeye yeni bir özellik eklendiğinde veya mevcut bir kod parçası yeniden düzenlendiğinde (refactoring), daha önce doğru çalışan bir davranışın bozulup bozulmadığını anlamanın en güvenilir yolu, o davranışı koruyan testleri tekrar çalıştırmaktır. Bu sayede geliştirici, kodun bir bölümüne dokunduğunda başka bir yerde beklenmedik bir bozulma (regresyon) yaratıp yaratmadığını dakikalar içinde görür; aksi hâlde bu tür hatalar genellikle üretim ortamına kadar fark edilmeden ilerleyebilir.

Yeni başlayan bir öğrenci için test yazmak çoğu zaman "ekstra bir iş yükü" gibi algılanır; oysa gerçekte tam tersi bir işlevi vardır. Test, kodun doğruluğunu her seferinde manuel olarak kontrol etme yükünü ortadan kaldıran bir güvence mekanizmasıdır. Bir metodu yazdıktan sonra onu doğrulayan bir test de yazmak, geliştiriciye "bu kod şu anda doğru çalışıyor ve gelecekte bunu bozarsam anında haberim olacak" güvenini verir. Bu bakış açısını erken kazanan öğrenciler, ileride daha büyük ve karmaşık projelerde çok daha rahat çalışır; çünkü kodun neresine dokunurlarsa dokunsun, testler onlara anında geri bildirim verir.

xUnit'in Temel Çalışma Mantığı: Proje, Sınıf ve Metot

xUnit ile çalışırken test edilecek kod ile testlerin kendisi genellikle ayrı projelerde tutulur. Uygulamanın iş mantığını içeren ana proje bir tarafta durur, testler ise ona referans veren bağımsız bir test projesinde yazılır. Bu ayrım tesadüfi değildir: testlerin ayrı bir projede yaşaması, hem üretim koduyla test kodunun birbirine karışmamasını hem de testlerin komut satırından veya derleme (build) sürecinden bağımsız biçimde çalıştırılabilmesini sağlar. Bu yapıyı ilk kez kuran biri için kavram karmaşası yaşanması normaldir; bu noktada canlı yazılım eğitimi sürecinde proje iskeletinin adım adım nasıl oluşturulduğunu görmek, soyut anlatımdan çok daha hızlı kavrayış sağlar.

Test projesi içinde her test senaryosu bir test sınıfı içindeki bir test metodu olarak ifade edilir. Bir test sınıfı, genellikle test edilen sınıfla aynı adı taşıyan ama sonuna "Tests" eklenmiş bir isimle oluşturulur; içindeki her metot ise tek bir davranışı doğrulamayı amaçlar. xUnit'in temel çalıştırma mantığı burada devreye girer: her test metodu, diğer test metotlarından bağımsız ve izole biçimde çalıştırılır. Bu izolasyon sayesinde bir testin başarısız olması, başka bir testin sonucunu etkilemez; her metot kendi başına anlamlı bir doğrulama birimidir.

xUnit, projede derlenen test sınıflarını ve metotlarını çalıştırmadan önce otomatik olarak tarar; bu sürece test keşfi (discovery) denir. Belirli özniteliklerle (attribute) işaretlenmiş metotlar bu tarama sırasında bulunur ve çalıştırılacak testler listesine eklenir. Geliştiricinin testleri manuel olarak bir listeye kaydetmesi gerekmez; xUnit bu işi kod üzerindeki işaretlemelere bakarak kendisi yapar. Bir sonraki bölümde bu işaretlemelerin en temel olanı olan [Fact] özniteliğini ayrıntılı biçimde ele alacağız.

[Fact] ile Sabit Senaryo Testleri Yazmak

[Fact] ile Sabit Senaryo Testleri Yazmak

xUnit'te [Fact] özniteliği, parametre almayan ve her zaman aynı, sabit bir senaryoyu doğrulayan testler için kullanılır. Bir metodun belirli, değişmeyen bir girdi-çıktı ilişkisini kontrol etmek istediğinde -örneğin "iki sayıyı topladığımda sonuç her zaman doğru olmalı" gibi tek bir durumu test ederken- [Fact] tam olarak bu amaca hizmet eder. Aynı senaryoyu farklı girdilerle tekrar tekrar test etmek gerekiyorsa bir sonraki bölümde ele alınacak [Theory] daha uygun bir seçenektir; ancak tek ve net bir davranışı doğrulamak için [Fact] en sade ve okunaklı yoldur.

Aşağıdaki örnekte basit bir Calculator sınıfı ve onun Add metodunu doğrulayan bir xUnit testi görülüyor:

public class Calculator
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

public class CalculatorTests
{
    [Fact]
    public void Add_IkiPozitifSayi_DogruToplamiDondurur()
    {
        var calculator = new Calculator();

        int sonuc = calculator.Add(3, 4);

        Assert.Equal(7, sonuc);
    }
}

Bu kod parçasında test metodu üç adımdan oluşur: önce test edilecek nesne oluşturulur (arrange), ardından test edilen metot çağrılır (act) ve son olarak sonucun beklenenle eşleşip eşleşmediği Assert.Equal ile kontrol edilir (assert). Assert.Equal(7, sonuc) satırı, beklenen değer olan 7 ile Add metodunun gerçekte döndürdüğü değeri karşılaştırır; değerler eşleşmezse xUnit bu testi başarısız olarak işaretler ve hangi değerin beklendiğini, hangisinin gerçekleştiğini açıkça raporlar. Bu üç adımlı düzen, ilerleyen bölümlerde inceleyeceğimiz daha karmaşık testlerde de aynı şekilde tekrarlanan temel bir kalıptır.

[Theory] ve [InlineData] ile Parametreli Testler

Bir metodu tek bir senaryoyla test etmek çoğu zaman yeterli değildir; gerçek dünyada aynı metot farklı girdilerle çağrılır ve her girdi kendi davranış riskini taşır. İşte tam bu noktada [Theory] devreye girer: aynı test mantığını, farklı girdi/çıktı kombinasyonlarıyla defalarca tekrar etmek yerine tek bir metotta parametreli olarak çalıştırmayı sağlar. [InlineData] ise bu parametreleri doğrudan metodun üzerine yazmanın en basit yoludur.

Önceki bölümde oluşturduğumuz Calculator sınıfına bir Divide metodu ekleyip, farklı sayı çiftleriyle davranışını tek bir test metodunda doğrulayalım:

public class Calculator
{
    public int Add(int a, int b) => a + b;

    public double Divide(int a, int b)
    {
        if (b == 0)
            throw new DivideByZeroException("Sıfıra bölme yapılamaz.");
        return (double)a / b;
    }
}

public class CalculatorTests
{
    [Theory]
    [InlineData(10, 2, 5)]
    [InlineData(9, 3, 3)]
    [InlineData(7, 2, 3.5)]
    public void Divide_FarkliSayiCiftleri_DogruSonucVerir(int a, int b, double beklenen)
    {
        var calculator = new Calculator();

        var sonuc = calculator.Divide(a, b);

        Assert.Equal(beklenen, sonuc);
    }
}

Burada dikkat edilmesi gereken fark şudur: [Fact] testi "bu tek senaryo her zaman doğru çalışmalı" der; [Theory] testi ise "bu metot, aşağıdaki tüm senaryolarda doğru çalışmalı" der. [Fact] ile üç ayrı senaryoyu test etmek isteseydik üç ayrı metot yazmamız gerekirdi; [Theory] ile bu senaryolar tek bir metodun altında satır satır listelenir ve xUnit her satırı bağımsız bir test çalıştırması olarak ele alır. Bu yaklaşım hem kod tekrarını azaltır hem de yeni bir senaryo eklemek istediğinizde tek yapmanız gereken şeyin yeni bir [InlineData] satırı eklemek olduğunu gösterir.

Bu mantığı gerçekten içselleştirmenin yolu, farklı metotlarla tekrar tekrar pratik yapmaktan geçer. Kendi projelerinizde string işleme, tarih hesaplama veya liste filtreleme gibi farklı senaryoları parametreli testlerle denemek istiyorsanız, kayıttan izlenebilen video eğitimler içindeki uygulamalı örnekler bu alışkanlığı adım adım pekiştirmenize yardımcı olur.

Assert Sınıfı ile Sonuçları Doğrulama

Assert Sınıfı ile Sonuçları Doğrulama

Bir testin gerçek değeri, aslında Assert sınıfının içinde saklıdır. Test metodunun geri kalanı yalnızca bir senaryo hazırlığıdır; asıl doğrulama, beklenen ile gerçekleşenin karşılaştırıldığı Assert satırında gerçekleşir. xUnit, farklı doğrulama ihtiyaçlarına karşılık gelen çeşitli Assert metotları sunar ve her biri niyetinizi kod okuyan bir başka geliştiriciye açıkça anlatır.

Assert.Equal(beklenen, gercek) iki değerin eşit olup olmadığını kontrol ederken, Assert.True(kosul) ve Assert.False(kosul) bir ifadenin mantıksal doğruluğunu sınar. Bir metodun beklenen durumlarda hata fırlatıp fırlatmadığını doğrulamak için ise Assert.Throws kullanılır. Örneğin Divide metoduna sıfır gönderildiğinde bir istisna fırlatılmasını bekliyorsak, bunu şu şekilde test edebiliriz:

public class CalculatorExceptionTests
{
    [Fact]
    public void Divide_SifiraBolme_IstisnaFirlatir()
    {
        var calculator = new Calculator();

        Assert.Throws(() => calculator.Divide(10, 0));
    }
}

Bu örnekte Assert.Throws, verilen kod bloğunu çalıştırır ve belirtilen istisna türünün gerçekten fırlatılıp fırlatılmadığını kontrol eder; fırlatılmazsa test başarısız olur. Bu, "hatalı girdi geldiğinde ne olmalı" sorusunu koda dökmenin en net yollarından biridir ve savunmacı programlama alışkanlığını doğrudan test seviyesinde pekiştirir.

Assert metotlarının en büyük katkısı, kodun ne yaptığını değil ne yapmaması gerektiğini de aynı netlikte ifade edebilmesidir. Bir test metodunu okuyan başka bir geliştirici, hangi Assert çağrısının kullanıldığına bakarak metodun hangi davranışı garanti ettiğini anında anlar; bu da testleri yalnızca hata yakalayan bir araç değil, aynı zamanda kodun canlı bir dokümantasyonu haline getirir. Doğru Assert metodunu seçmek, test yazarken göz ardı edilmemesi gereken küçük ama etkili bir alışkanlıktır.

xUnit, JUnit ve pytest: Kavramsal Bir Karşılaştırma

Birim test mantığı dil değiştikçe isim değiştirir ama temel fikir aynı kalır: bir senaryoyu izole et, çalıştır, sonucu doğrula. xUnit'teki [Fact] ve [Theory] anotasyonlarının Java dünyasındaki karşılığı JUnit'te @Test ve @ParameterizedTest ile kurulur; her iki ekosistem de "sabit senaryo" ile "parametreli senaryo" ayrımını benzer bir anotasyon mantığıyla çözer. Python tarafında ise pytest, anotasyon yerine sade fonksiyon isimlendirmesine ve dekoratörlere dayanır; bir fonksiyonun adı test_ ile başladığında pytest onu otomatik olarak keşfeder, parametreli senaryolar için ise @pytest.mark.parametrize dekoratörü kullanılır.

Kavram xUnit (C#) JUnit (Java) pytest (Python)
Sabit senaryo testi [Fact] @Test test_ ile başlayan fonksiyon
Parametreli test [Theory] + [InlineData] @ParameterizedTest + @ValueSource/@CsvSource @pytest.mark.parametrize
Doğrulama/assert biçimi Assert.Equal, Assert.True, Assert.Throws assertEquals, assertTrue, assertThrows sade assert ifadesi
Test keşfi Test projesindeki anotasyonlu metotlar otomatik bulunur Anotasyonlu metotlar sınıf taranarak bulunur Dosya ve fonksiyon adlandırma kuralına göre otomatik keşif

Bu tablodan çıkan en önemli sonuç, üç ekosistemin de aslında aynı kavramsal iskeleti farklı sözdizimleriyle ifade etmesidir. xUnit'i öğrenen bir geliştirici, "sabit senaryo" ve "parametreli senaryo" ayrımını zaten kavramış olduğu için JUnit'e geçtiğinde yalnızca anotasyon isimlerini öğrenmesi yeterli olur; mantık zaten yerleşiktir. Bu nedenle C# ile test yazmayı öğrenmek, yalnızca .NET dünyasında değil, Java tarafında da işinize yarayacak bir zihinsel model kurar. Nitekim birebir Java dersleri kapsamında JUnit ile test yazmayı öğrenen öğrenciler, xUnit'teki bu yapıyı gördüklerinde kavramların ne kadar örtüştüğünü kolayca fark eder.

pytest'in dekoratör tabanlı, sınıf zorunluluğu olmayan yaklaşımı ise C# ve Java'nın anotasyon/sınıf ağırlıklı yapısına kıyasla daha minimal görünse de, altında yatan mantık birebir aynıdır: bir girdi kümesi tanımla, beklenen sonucu belirle, doğrula. Hangi dilde çalışırsanız çalışın, bu üçlü adım test yazmanın değişmeyen omurgasıdır.

İlk xUnit Testini Yazma: Adım Adım

Buraya kadar anlatılan Fact, Theory ve Assert mantığını tek bir akışta birleştirmenin en pratik yolu, sıfırdan bir test projesi kurup ilk testi baştan sona yazmaktır. Aşağıdaki adımlar, önceki bölümlerde gösterilen kod örneklerine atıfla, bir C# çözümünde xUnit testlerinin nasıl hayata geçirildiğini sırasıyla özetler.

  1. Test projesi oluşturma: Ana uygulama projenizin yanına, yalnızca test kodlarını barındıracak ayrı bir proje eklersiniz. Bu proje, üretim kodundan bağımsız olarak derlenir ve çalıştırılır; böylece test bağımlılıkları ana uygulamaya karışmaz.
  2. Test edilecek sınıfa referans verme: Test projesi, doğrulamak istediğiniz sınıfların bulunduğu ana projeyi referans olarak eklemelidir. Bu adım atlanırsa, test metodu içinde ilgili sınıfa erişim mümkün olmaz ve derleme hatası alırsınız.
  3. Test sınıfı ve metodunu yazma: Referans tanımlandıktan sonra, test edilecek her sınıf için anlamlı isimlendirilmiş bir test sınıfı oluşturulur. Metot isimleri, hangi senaryonun sınandığını okuyan herkesin anlayacağı netlikte yazılmalıdır; bu, ilerleyen bölümlerde bahsedilen "sabit senaryo" ve "parametreli senaryo" ayrımının netleştiği yerdir.
  4. [Fact] veya [Theory] seçimini yapma: Test edilen davranış tek bir girdi-çıktı ilişkisiyle sınanabiliyorsa [Fact] yeterlidir. Aynı mantığı birden fazla girdi kümesiyle doğrulamanız gerekiyorsa, önceki bölümde gösterilen [Theory] ve [InlineData] kombinasyonuna geçilir. Bu seçim, testin okunabilirliğini ve bakımını doğrudan etkiler.
  5. Testleri çalıştırıp sonucu yorumlama: Test projesi çalıştırıldığında her metot ayrı ayrı işletilir ve geçti/kaldı bilgisi raporlanır. Kalan bir testin hangi Assert ifadesinde başarısız olduğunu görmek, hatanın kaynağını üretim kodunda aramaya başlamadan önce net bir ipucu verir.

Bu beş adımı birkaç kez tekrar ettikten sonra, yeni bir sınıf yazarken test sınıfını da eş zamanlı oluşturmak neredeyse otomatik bir refleks hâline gelir. Önemli olan, ilk denemede mükemmel bir test paketi kurmaya çalışmamak; küçük ve anlaşılır testlerle başlayıp kapsamı zamanla genişletmektir.

Test Yazma Alışkanlığını Kalıcı Hale Getirmek

Birim test yazmak, başlangıçta ekstra bir yük gibi görünse de zamanla kod yazma sürecinin doğal bir parçasına dönüşür. Bir metot yazıldığında akla ilk gelen sorunun "bu doğru çalışıyor mu?" değil, "bunu nasıl test ederim?" olması, deneyimli bir geliştiricinin en belirgin alışkanlıklarından biridir. Bu dönüşüm bir gecede olmaz; küçük adımlarla, tek bir sınıfı test etmekle başlayıp giderek daha karmaşık senaryolara doğru ilerleyerek gerçekleşir.

Yeni başlayanlar için en sağlıklı yaklaşım, her oturumda bütün projeyi test etmeye çalışmak yerine, o gün yazılan tek bir metodu veya sınıfı test etmektir. Bu şekilde test yazma süreci, kod yazma sürecinden kopuk bir "sonradan eklenen" adım olmaktan çıkar ve geliştirmenin ayrılmaz bir parçası hâline gelir. Zamanla, bir hatayı fark ettiğinizde önce onu tekrar üretecek bir test yazma, sonra kodu düzeltme alışkanlığı da buna eklenir; bu, test odaklı geliştirmenin en temel pratiklerinden biridir.

Bu noktada kendi seviyenizi objektif biçimde görmek de faydalı bir adımdır. C# dilindeki genel kavramlara ne kadar hâkim olduğunuzu anlamak için C# bilgi testini çözmek, hangi konularda daha fazla pratiğe ihtiyacınız olduğunu net biçimde ortaya koyar. Test yazma pratiğiyle birlikte bu tür temel bilgi kontrolleri, öğrenme sürecinde nerede olduğunuzu görmenizi kolaylaştırır.

Unutulmaması gereken nokta şudur: birim test yazmayı öğrenmek, tek bir makaleyle veya tek bir projeyle tamamlanan bir süreç değildir. Her yeni sınıf, her yeni senaryo, bu alışkanlığı biraz daha pekiştirir. Küçük adımlarla, sabırla ve düzenli pratikle ilerleyen bir geliştirici, bir süre sonra test yazmanın yavaşlatan değil hızlandıran bir adım olduğunu fark eder.

Sık Sorulan Sorular

xUnit nedir ve C# projelerinde neden tercih edilir?

xUnit, C# ve .NET tabanlı projelerde birim testleri yazmak için kullanılan bir test kütüphanesidir. Öznitelik tabanlı yapısı sayesinde test metotları sade biçimde işaretlenir ve sabit veya parametreli senaryolar aynı çatı altında yönetilebilir.

[Fact] ile [Theory] arasındaki temel fark nedir?

[Fact], tek bir girdi-çıktı ilişkisini sınayan sabit senaryo testlerinde kullanılır. [Theory] ise aynı test mantığını [InlineData] ile beslenen birden fazla girdi kümesiyle çalıştırmak için tercih edilir; böylece benzer testleri tekrar tekrar yazmak gerekmez.

Assert.Throws hangi durumlarda kullanılır?

Assert.Throws, bir metodun belirli koşullar altında beklenen bir istisnayı fırlatıp fırlatmadığını doğrulamak için kullanılır. Geçersiz girdi veya hatalı durum senaryolarında kodun sessizce yanlış davranmak yerine açıkça hata bildirmesi gerektiği durumlarda kritik bir kontrol noktasıdır.

xUnit ile JUnit arasındaki kavramsal fark nedir?

Her iki kütüphane de öznitelik tabanlı test tanımlama mantığını paylaşır; bir metodun test olduğunu belirtme, kurulum ve doğrulama adımları kavramsal olarak benzerdir. Farklar daha çok dile özgü sözdizimi ve öznitelik isimlendirmesinde ortaya çıkar, temel test felsefesi ortaktır.

pytest'te xUnit'teki [Fact]/[Theory] yapısına karşılık gelen yaklaşım nedir?

pytest'te öznitelik yerine düz fonksiyonlar ve assert ifadeleri kullanılır; parametreli testler için ise fonksiyon üzerine eklenen bir dekoratörle birden fazla girdi kümesi tek bir test fonksiyonuna bağlanır. Amaç xUnit'teki Theory/InlineData ile aynıdır: tekrarı azaltmak.

Birim test yazmaya yeni başlayan biri nereden başlamalı?

En basit ve tek sorumluluğu olan bir sınıfla başlamak, o sınıf için birkaç [Fact] testi yazmak ve sonuçları Assert ile doğrulamak yeterlidir. Karmaşık senaryolara ve parametreli testlere, temel mantık oturduktan sonra geçilmelidir.

Test projesini ana projeden ayrı tutmak gerekli mi?

Evet, test kodunun ayrı bir projede tutulması, üretim kodunun test bağımlılıklarından bağımsız kalmasını sağlar. Bu ayrım, projenin dağıtım paketinin sade kalmasına ve test kodunun kendi içinde düzenli yönetilmesine yardımcı olur.

xUnit ile birim test yazmanın mantığı, aslında kodun her adımda kendi kendini doğrulamasını sağlamaktan ibarettir; bu alışkanlık ne kadar erken kazanılırsa, ilerideki projelerde o kadar az sürprizle karşılaşılır. Test yazma disiplinini Java veya Python üzerinden canlı bir ortamda pekiştirmek isteyenler için online yazılım eğitimi sayfası, bu pratiği yapılandırılmış bir müfredatla sürdürmek isteyenlere uygun bir başlangıç noktası sunar.

Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

İlgili Eğitimler

Berk Keskin — Yazılım Geliştirici ve Eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; bugün öğrencinin seviyesine ve hedefine göre şekillenen sürdürülebilir öğrenme sistemleri tasarlıyor. 300'den fazla kişiye ezber değil, düşünerek kod yazmayı öğretti — Berk Akademi'de izlemeye değil üretmeye dayalı öğrenme kültürünü o kuruyor.

WhatsApp Hemen Ara