CodeBlanks Logo Icon CodeBlanks

DI ve test

C# kursu · İleri seviye · Ders 82/83

DI container ve xUnit testlerini kurarsın.

DI ve test

Reflection keşfi çalışıyor; ancak komutları elle Activator.CreateInstance ile örnekliyoruz. Şimdi küçük bir bağımlılık enjeksiyonu kabı ekleyeceğiz: Container sınıfı Register<T>(string, Func<T>) ile kayıt yapar, Resolve<T>(string) ile örneği döndürür.

Aynı zamanda küçük bir test ekleyeceğiz: TestHelloCommand metodu container'dan "hello" komutunu çözer, çalıştırır ve sonucun "Merhaba" olduğunu denetler. Bu, xUnit yerine geçen bir el yapımı doğrulamadır; proje boyunca tek dosya kalabilmemizi sağlar.

El yapımı test

Gerçek projelerde test ayrı bir derlemede xUnit ile yazılır. Burada tek dosya kalmak için TestHelloCommand statik metodunu yazıyoruz: container'dan komutu çözer, ExecuteAsync().Result ile sonucu alır ve if (result != "Merhaba") throw new Exception(...) ile doğrular. Başarılıysa Console.WriteLine("Test passed: hello") yazar.

Bu yapı, gerçek bir test çerçevesinin yaptığını küçük ölçekte taklit eder: doğrulama, başarısızlıkta istisna, başarıda bildirim. Birim testi alışkanlığını tek dosyada sürdürmek için pratik bir yoldur.

Uygulama Container ve test ekle

Bir Container sınıfı tanımla; özel Dictionary<string, Func<ICommand>> _factories alsın. Register<T>(string name, Func<T> factory) where T : class, ICommand metodu fabrikayı kayıt altına alsın; Resolve<T>(string name) where T : class metodu fabrikayı çağırıp sonucu (T) türüne çevirsin. Main'de bir Container yarat, Register<ICommand>("hello", () => new HelloCommand()) ile kayıt yap, TestHelloCommand(container) çağır, sonra Resolve<ICommand>("hello") ile komutu çöz ve await cmd.ExecuteAsync() sonucunu yazdır. TestHelloCommand metodu Resolve<ICommand>("hello") ile komutu çözsün, ExecuteAsync().Result ile sonucu alsın, "Merhaba" dışında ise throw new Exception(...) fırlatsın, değilse Console.WriteLine("Test passed: hello") yazsın.

Örnek çözümü göster
class Container { private readonly Dictionary<string, Func<ICommand>> _factories = new(); public void Register<T>(string name, Func<T> factory) where T : class, ICommand => _factories[name] = () => factory(); public T Resolve<T>(string name) where T : class => (T)_factories[name](); } yaz. Main'de: var container = new Container(); container.Register("hello", () => new HelloCommand()); TestHelloCommand(container); var cmd = container.Resolve<ICommand>("hello"); Console.WriteLine(await cmd.ExecuteAsync()); static void TestHelloCommand(Container container) { var cmd = container.Resolve<ICommand>("hello"); var result = cmd.ExecuteAsync().Result; if (result != "Merhaba") throw new Exception($"Beklenen: Merhaba, gerçek: {result}"); Console.WriteLine("Test passed: hello"); }
Örnek çözüm:
using System;
using System.Threading.Tasks;
using System.Reflection;
using System.Collections.Generic;

[Command("hello")]
class HelloCommand : ICommand
{
    public async Task<string> ExecuteAsync()
    {
        await Task.CompletedTask;
        return "Merhaba";
    }
}

class CommandAttribute : Attribute
{
    public string Name { get; }
    public CommandAttribute(string name) => Name = name;
}

interface ICommand
{
    Task<string> ExecuteAsync();
}

class Container
{
    private readonly Dictionary<string, Func<ICommand>> _factories = new();
    public void Register<T>(string name, Func<T> factory) where T : class, ICommand =>
        _factories[name] = () => factory();
    public T Resolve<T>(string name) where T : class => (T)_factories[name]();
}

class Program
{
    static async Task Main()
    {
        var container = new Container();
        container.Register("hello", () => new HelloCommand());
        TestHelloCommand(container);
        var cmd = container.Resolve<ICommand>("hello");
        Console.WriteLine(await cmd.ExecuteAsync());
    }

    static void TestHelloCommand(Container container)
    {
        var cmd = container.Resolve<ICommand>("hello");
        var result = cmd.ExecuteAsync().Result;
        if (result != "Merhaba")
            throw new Exception($"Beklenen: Merhaba, gerçek: {result}");
        Console.WriteLine("Test passed: hello");
    }
}

Kendini test et

  1. DI kayıt çağrısını tamamla

    container.Register____<ICommand>("hello", () => new HelloCommand());
    Cevabı göster
    container.Register<ICommand><ICommand>("hello", () => new HelloCommand());
  2. Container.Resolve<T>("hello") ne döndürür?

    • HelloCommand türünü
    • Kayıtlı fabrikadan oluşturulmuş ICommand örneğini
    • Bir Type nesnesini
    • Boş bir referansı
    Cevabı göster

    Bir Type nesnesini — Doğru. Resolve<T> kayıtlı fabrikayı çağırıp ICommand örneğini döndürür.

  3. DI ve test terimlerini eşleştir

    Container
    Kayıt ve çözme kabı
    Register<T>
    Fabrika kaydı
    Resolve<T>
    Örnek çözme
    TestHelloCommand
    Doğrulama metodu

İleri seviye bölümündeki tüm dersler