C# İle Unit Testing İçin Moq Kütüphanesi Kullanımı Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

Moq kütüphanesini kullanabilmek için öncelikle .NET SDK'sının yüklü olduğu bir geliştirme ortamına ihtiyacınız vardır. Visual Studio 2026 veya VS Code üzerinde .NET 8/9+ sürümleri ile çalışmanız önerilir. Projenize Moq kütüphanesini eklemek için terminal üzerinden aşağıdaki komutu kullanabilirsiniz.

dotnet add package Moq

Bu komut, projenizin .csproj dosyasına Moq'un en güncel sürümünü ekleyecektir. Ayrıca test projenizde xUnit veya NUnit gibi bir test framework'ünün kurulu olduğundan emin olmalısınız. Kurulum tamamlandıktan sonra, test sınıflarınızın başına using Moq; ifadesini ekleyerek kütüphaneyi kullanmaya başlayabilirsiniz.

Temel Kavram: Neden Moq Kullanmalıyız?

Yazılım geliştirmede "Mocking", gerçek bir nesnenin davranışını taklit eden sahte bir nesne oluşturma işlemidir. Örneğin, bir kullanıcı kayıt servisini test ederken, gerçek bir SQL veritabanına bağlanmak yerine, veritabanı işlemlerini gerçekleştiren arayüzü "mock"layarak veritabanı bağımlılığını ortadan kaldırırız. Bu, testlerin hem çok daha hızlı çalışmasını hem de dış faktörlerden etkilenmemesini sağlar.

Özellik Gerçek Nesne Moq (Sahte Nesne)
Hız Yavaş (I/O, Network) Çok Hızlı (Bellek içi)
Bağımlılık Yüksek İzole
Tahmin edilebilirlik Düşük (Veri değişebilir) Yüksek (Kontrollü veri)

Adım Adım Moq ile Nesne Oluşturma ve Yapılandırma

İlk adım olarak, test etmek istediğimiz bir arayüz tanımlayalım. Bu arayüz, bir e-posta servisinin imzasını temsil etsin. Ardından, Moq ile bu arayüzü nasıl taklit edeceğimizi görelim.

public interface IEmailService {
    bool SendEmail(string to, string subject);
}

// Test sınıfı içinde mock nesnesi oluşturma
var mockEmailService = new Mock();

Yukarıdaki kod bloğu, IEmailService arayüzünden bir mock nesnesi oluşturur. Ancak bu nesne henüz bir davranışa sahip değildir. Bir metodun çağrıldığında ne döndüreceğini belirlemek için Setup metodunu kullanırız.

mockEmailService.Setup(x => x.SendEmail("test@example.com", "Merhaba"))
                .Returns(true);

Bu yapılandırma ile, SendEmail metodu belirtilen parametrelerle çağrıldığında geriye true değerinin dönmesini sağladık. Bu, test senaryolarınızda farklı durumları (başarılı/başarısız) simüle etmenize olanak tanır.

Metot Çağrılarını Doğrulama (Verification)

Testin başarılı sayılması için sadece dönen değer yeterli değildir; bazen bir metodun gerçekten çağrılıp çağrılmadığını da kontrol etmeniz gerekir. Moq, Verify metodu ile bu kontrolü kolaylaştırır.

// Servisi çalıştır
var result = service.DoWork();

// Metodun tam olarak 1 kez çağrıldığını doğrula
mockEmailService.Verify(x => x.SendEmail(It.IsAny(), It.IsAny()), Times.Once);

It.IsAny() ifadesi, parametre değeri ne olursa olsun eşleşme sağlar. Times.Once ise metodun sadece bir kez çağrıldığını garanti eder. Bu yaklaşım, iş mantığınızın doğru akışta ilerlediğinden emin olmanızı sağlar.

İleri Seviye Moq Kullanımı: Callback ve Exception

Bazen bir metot çağrıldığında sadece değer dönmesini değil, aynı zamanda bir işlem yapmasını veya hata fırlatmasını isteyebilirsiniz. Callback ve Throws metotları bu durumlar için idealdir.

// Hata fırlatma örneği
mockEmailService.Setup(x => x.SendEmail(It.IsAny(), It.IsAny()))
                .Throws(new Exception("E-posta sunucusu kapalı!"));

// Callback kullanımı
mockEmailService.Setup(x => x.SendEmail(It.IsAny(), It.IsAny()))
                .Callback((to, sub) => Console.WriteLine($"Gönderiliyor: {to}"))
                .Returns(true);

Throws kullanımı, kodunuzun hata durumlarında nasıl davrandığını (hata yönetimi) test etmek için kritik öneme sahiptir. Callback ise mock edilen metodun içine bir loglama veya yan işlem eklemenize yardımcı olur.

Güvenlik Uyarısı: Testlerinizde asla gerçek kullanıcı verilerini, şifreleri veya hassas API anahtarlarını kullanmayın. Mock nesneleri her zaman dummy (anlamsız) verilerle doldurun. Üretim ortamında çalışacak kodlarınızda ise her zaman güvenli şifreleme (örneğin Argon2 veya PBKDF2) yöntemlerini tercih edin.

Sıkça Sorulan Sorular

Moq ile statik metotları mocklayabilir miyim?

Hayır, Moq kütüphanesi doğası gereği arayüzler ve sanal (virtual) metotlar üzerinde çalışır. Statik metotları mocklamak için farklı yaklaşımlar (örneğin Proxy desenleri veya farklı kütüphaneler) gerekebilir.

Mock nesneleri neden interface üzerinden kullanılmalı?

Interface kullanımı, kodunuzun gevşek bağlı (loosely coupled) olmasını sağlar. Bu sayede test edilebilirliği artırır ve bağımlılıkları (Dependency Injection) yönetmeyi kolaylaştırır.

Testlerim çok yavaş çalışıyor, sebebi ne olabilir?

Eğer testlerinizde Moq kullanmanıza rağmen yavaşlık yaşıyorsanız, mock nesneleri yerine yanlışlıkla gerçek veritabanı veya ağ bağlantıları kullanıyor olabilirsiniz. Mock nesnelerinizin bağımlılıkları doğru şekilde enjekte edildiğinden emin olun.

Moq'da "Strict" modu nedir?

MockBehavior.Strict kullanıldığında, eğer bir metodun davranışı önceden Setup edilmemişse, Moq bir hata fırlatır. Bu, testlerinizde beklenmedik çağrıları yakalamak için oldukça faydalıdır.

Aynı arayüzü farklı testlerde nasıl kullanırım?

Test sınıflarınızda Setup metodunu kullanarak her test metodu öncesinde yeni bir Mock nesnesi oluşturarak temiz bir test ortamı (isolation) sağlayabilirsiniz.

Moq Kullanımında Yaygın Hatalar ve Performans İpuçları

Moq kütüphanesi ile test yazarken, özellikle büyük projelerde performans kayıpları veya testlerin kırılgan hale gelmesi gibi sorunlarla karşılaşabilirsiniz. Bu durum genellikle kütüphanenin yanlış kullanımından kaynaklanır. İşte testlerinizi daha hızlı ve sürdürülebilir kılacak bazı stratejiler:

Mock Nesnelerinin Aşırı Kullanımı (Over-Mocking)

Her bağımlılık için bir Mock nesnesi oluşturmak, testlerinizin karmaşıklığını artırır. Eğer bir sınıfın bağımlılığı basit bir veri taşıyıcı (POCO) ise veya gerçek bir implementasyonun kullanımı testin hızını etkilemiyorsa, Mock kullanmak yerine gerçek nesneyi kullanmayı tercih edin.

Setup Metotlarının Gereksiz Tekrarı

Testlerinizde sürekli aynı Setup yapılandırmasını yapıyorsanız, bu durum kodun okunabilirliğini azaltır. Bunun yerine, test sınıfınızın içinde bir private yardımcı metot oluşturarak yapılandırmayı merkezileştirin.

private Mock CreateDefaultOrderMock()
{
    var mock = new Mock();
    mock.Setup(x => x.IsValid(It.IsAny())).Returns(true);
    return mock;
}

[Fact]
public void ProcessOrder_ShouldReturnTrue_WhenOrderIsValid()
{
    var mock = CreateDefaultOrderMock();
    // Test işlemleri...
}

Moq ile Hata Ayıklama (Debugging) Stratejileri

Testleriniz beklenmedik şekilde başarısız olduğunda, Mock nesnesinin neden beklenen değeri döndürmediğini anlamak zor olabilir. Moq, bu süreçte size yardımcı olacak bazı araçlar sunar.

Mock Nesnesinin Çağrı Kayıtlarını İnceleme

Test başarısız olduğunda, Mock nesnesinin hangi parametrelerle çağrıldığını görmek için Invocations özelliğini kullanabilirsiniz. Bu, özellikle It.Is filtrelerinizin neden eşleşmediğini bulmanıza yardımcı olur.

[Fact]
public void Debugging_Example()
{
    var mock = new Mock();
    var service = new UserManager(mock.Object);

    service.UpdateUser(10, "Yeni İsim");

    // Hangi çağrıların yapıldığını görmek için:
    foreach (var invocation in mock.Invocations)
    {
        Console.WriteLine($"Metot: {invocation.Method.Name}, Argüman: {invocation.Arguments[0]}");
    }
}

Strict Modu ile Beklenmedik Çağrıları Yakalama

Eğer testinizin, yapılandırılmamış hiçbir metodun çağrılmadığından emin olmasını istiyorsanız MockBehavior.Strict kullanın. Bu mod, tanımlanmamış bir metot çağrıldığında testin anında hata vermesini sağlar, böylece "sessiz hata" durumlarının önüne geçersiniz.

// Strict mod ile tanımlanmamış metot çağrılırsa test başarısız olur
var mock = new Mock(MockBehavior.Strict);

// Bu satır olmazsa, test hata fırlatacaktır
mock.Setup(x => x.Save(It.IsAny())).Verifiable();

var service = new OrderService(mock.Object);
service.Process(new Order()); // Eğer Save metodu çağrılmazsa veya başka bir metot çağrılırsa test çöker.

Bu ileri düzey teknikler, test paketinizin kalitesini artıracak ve CI/CD süreçlerinde daha güvenilir sonuçlar almanızı sağlayacaktır. Unutmayın, iyi bir test, sadece doğruluğu kanıtlayan değil, aynı zamanda hata durumunda nedenini açıkça belirten testtir.

Sonuç

C# ile unit testing süreçlerinde Moq kütüphanesi, karmaşık bağımlılıkları yönetmek ve kodunuzun her parçasını izole bir şekilde test etmek için en verimli yoldur. Bu rehberde öğrendiğiniz Setup, Verify, Callback ve Throws gibi temel yetenekler, profesyonel bir yazılım geliştiricinin test araç çantasının temelini oluşturur. Bir sonraki adım olarak, bu bilgileri kendi projelerinizdeki servis katmanlarına entegre edebilir ve "Test Driven Development" (TDD) metodolojisini uygulamaya başlayabilirsiniz. Unutmayın, iyi yazılmış testler, gelecekteki hataları bugünden engellemenin en güvenilir yoludur.

Bu yazıya tepkinizi paylaşın:
Deniz Arıkan

On yıldır pratik yaşam çözümleri ve ev ekonomisi üzerine editörlük yapıyorum. Karmaşık süreçleri herkesin uygulayabileceği basit adımlara dönüştürme konusunda uzmanım.

Yorumlar (0)

Yorum Yaz