Blog Kategorileri

Kaliteli Test Senaryoları için Gelişmiş xUnit Teknikleri

Unit test yalnızca birçok test türünden birisidir. Bu nedenle konumuzun detaylarına geçmeden önce test türlerini tekrardan hatırlayalım.

  • Birim (Unit) Testleri: Kodun en küçük birimini, genellikle bir metot veya fonksiyonu test eder. Bağımlılıklarından izole edilmiş birim testi için gerektiğinde mock kullanılır. Her bir birim için birden fazla test bulunmalıdır: tipik girdiler ve beklenen çıktılar için olanlar, sınırları test etmek için aşırı girdi değerleri için olanlar ve istisna işleme test etmek için bilerek yanlış girdiler için olanlar.
  • Entegrasyon (Integration) Testleri: Küçük birimlerin ve daha büyük bileşenlerin tek bir yazılım parçası olarak çalışıp çalışmadığını test eder. Bazı durumlarda kaynak koduna sahip olmadığınız harici bileşenlerle entegrasyon içerir.
  • Sistem (System) Testleri: Yazılımınızın çalışacağı tüm sistem ortamını test eder.
  • Performans (Performance) Testleri: Yazılımınızın performansını test eder; örneğin, kodunuzun bir web sayfasını 20 milisaniyenin altında bir sürede bir ziyaretçiye geri dönmesi gerekebilir.
  • Yük (Load) Testleri: Yazılımınızın gereken performansı korurken aynı anda kaç isteği karşılayabileceğini test eder; örneğin, bir web sitesine 10.000 eş zamanlı ziyaretçi.
  • Kullanıcı Kabul (User Acceptance) Testleri: Kullanıcıların yazılımınızı kullanarak işlerini mutlu bir şekilde tamamlayıp tamamlayamadığını test eder.

Şimdi xUnit hakkındaki bilgimizi genişletelim ve sağlam test senaryoları oluşturmak için gelişmiş teknikleri keşfedelim.

InlineData ve MemberData ile Veriye Dayalı Testler

xUnit’in [Theory] attribute ile, giriş değerlerini sağlamak için [InlineData] veya [MemberData] kullanılarak veriye dayalı testler oluşturulmasına olanak tanır:

  • InlineData, birim testlerde kullanılan bir özelliktir ve test metodunun niteliğinde doğrudan içeride veri değerleri sağlar. Test metoduna çeşitli girdi değerlerini kolayca sağlamak için kullanılır.
        [Theory]
        [InlineData(1, 2, 3)]
        [InlineData(-1, -2, -3)]
        public void Add_TwoNumbers_ReturnsSum(int a, int b, int expectedResult)
        {
            // Test kodu
        }
  • MemberData, Bu özellik, bir test metoduna test verilerini sağlamak için bir üye (property veya method) belirtir. Bu üye, her test durumu için bir nesne dizisi döndürmelidir. Özellikle büyük veri setleri veya dinamik olarak oluşturulan verilerle çalışırken MemberData çok kullanışlı olabilir. Test metodu, MemberData özelliği kullanılarak tanımlanan bir üyenin döndürdüğü verilerle çalışır.
public static IEnumerable<object[]> TestData
{
    get
    {
        yield return new object[] { 1, 2, 3 };
        yield return new object[] { -1, -2, -3 };
    }
}

[Theory]
[MemberData(nameof(TestData))]
public void Add_TwoNumbers_ReturnsSum(int a, int b, int expectedResult)
{
    // Test kodu
}

Class ve Collection Kullanarak Test İçeriklerini Paylaşma

xUnit’te test bağlamı paylaşımı, kod tekrarını önlemeye ve tutarlı kurulum/sökme işlemlerini sağlamaya yardımcı olan araçlar aracılığıyla gerçekleştirilir.

  • Class Fixture, bir sınıftaki tüm testler arasında bir bağlamın tek bir örneğini paylaşır. Bir sınıf fixture’ını kullanmak için, T’nin bağlam türü olduğu IClassFixture<T> interface’ini uygulayan bir sınıf oluşturun.
public class MyTestFixture : IClassFixture<MyContext>
{
    // Test kodu
}
  • Collection Fixture, birden fazla test sınıfı arasında bir bağlam örneğini paylaşır ve kaynak yoğun kurulumlar için kullanışlıdır. Bir koleksiyon fixture’ını kullanmak için, ICollectionFixture<T> interface’ini uygulayan bir koleksiyon tanımı sınıfı oluşturun ve ardından [CollectionDefinition] attribute’ını uygulayın.
[CollectionDefinition("MyCollection")]
public class MyCollection : ICollectionFixture<MyContext>
{
}

[Collection("MyCollection")]
public class MyTest1
{
    // Test kodu
}

[Collection("MyCollection")]
public class MyTest2
{
    // Test kodu
}

xUnit’te Testleri Atlama ve Koşullu Test Yürütme

Bazen belirli koşullara bağlı olarak testleri atlamak veya koşullu olarak yürütmek isteyebiliriz. xUnit bunu kolaylaştırmak için seçenekler sunar:

  • Skipping test (Testlerin Atlanmas): Bir testi atlamak için Skip özniteliğini kullanabilirsiniz. Bu öznitelik, Skip metoduyla birlikte kullanılır ve atlanacak testin nedenini belirtmenize olanak tanır.
[Fact(Skip = "Bu test henüz tamamlanmadı.")]
public void MySkippedTest()
{
    // Test kodu
}
  • Conditional test execution (Koşula Bağlı Test Yürütme): Testlerin koşula bağlı olarak yürütülmesi için SkipIf veya Theory ile birlikte koşul ifadeleri kullanılabilir.
[Fact]
[SkipIf(condition: true, reason: "Bu test belirli bir koşul nedeniyle atlanıyor.")]
public void MyConditionalTest()
{
    // Test kodu
}

Test Sonuçlarını Özelleştirme: xUnit Logger ve Report

Bazı senaryolarda, çeşitli formatlarda raporlar veya loglar oluşturmak için test çıktısını özelleştirmek isteyebilirsiniz. xUnit bunu bir logger ve report sistemi aracılığıyla destekler:

  • Logger: Test çıktısını özel konumlara yönlendirmek veya ek bilgiler eklemek için ITestOutputHelper interface’ini uygulayın.
  public class MyTests
  {
      private readonly ITestOutputHelper _output;

      public MyTests(ITestOutputHelper output)
      {
          _output = output;
      }

      [Fact]
      public void TestWithCustomOutput()
      {
          _output.WriteLine("Custom log message");
          // Test kodu
      }
  }
  • Report: IMessageSinkWithTypes interface’ini uygulanarak özel raporlar oluşturulabilir, böylece test çıktısı ve biçimlendirme üzerinde daha ayrıntılı kontrol sağlanır.
  public class MyCustomReporter : IMessageSinkWithTypes
  {
      public bool OnMessageWithTypes(IMessageSinkMessage message, HashSet<string> messageTypes)
      {
          // Custom test report logic here
      }
  }

Belirsiz Testlerle Başa Çıkmak İçin Bazı İpuçları

  • Tekrarlanabilirlik: Testlerinizi mümkün olduğunca tekrarlanabilir hale getirin. Aynı girdilerle her zaman aynı çıktıları üretecek şekilde tasarlayın.
  • İzolasyon: Testlerinizi diğer testlerden ve dış etkenlerden izole edin. Testler arasında bağımlılıkları minimize edin ve testin sonucunu etkileyebilecek dış etkenlerden kaçının.
  • Rastgelelikleri Kontrol Edin: Testlerde rastgelelik içeren öğeleri belirleyin ve bu rastgelelikleri kontrol altında tutun. Örneğin, rastgele veri oluşturma işlemlerini sabit seed değerleri kullanarak kontrol edebilirsiniz.
  • Gecikmeleri Yönetin: Testlerde kullanılan beklemeleri (wait) ve zamanlamaları yönetin. Gerekli olan yerlerde gecikmeler ekleyin ancak bu gecikmelerin maksimum süresini belirleyin.
  • Loglama ve Hata İncelemesi: Testlerin çalışma sırasında ürettikleri çıktıları (log) detaylı bir şekilde inceleyin. Belirsiz testlerin nedenlerini ve belirsizlikleri tespit etmek için loglamayı kullanın.
  • Sistemi Temiz Tutun: Testlerin çalışmasını etkileyebilecek sistem durumlarını temizleyin veya sıfırlayın. Örneğin, veritabanı durumunu, dosya sistemini veya belleği testler arasında temizleyin.
  • Sürdürülebilirlik ve Bakım: Testlerinizi düzenli olarak gözden geçirin ve gerektiğinde güncelleyin. Belirsizlikleri azaltmak için testlerinizi ve test senaryolarını iyileştirin.
Last Updated : 01/05/2024

C# Birim Testleri için Mocking ve Moq’a Giriş

C# Unit Test

2023 © Coding, Developed by alkanfatih.com