Basit Bir Mock Framework Geliştirelim 2

2023-05-11 | #diy-mocking-framework #do-it-yourself #mock #net #reflection

Artık interface lerle çalışalım. Öncelikle, System.Reflection.DispatchProxy‘yi kullanacağız. Bu, bir proxy sınıfı oluşturmanıza ve ona method çağrılarını yönlendirmenize olanak sağlar. DispatchProxy‘yi kullanarak belirli bir arayüzün metotlarını mocklayalım. using System; using System.Collections.Generic; using System.Reflection; public class Mock<T> : DispatchProxy { private readonly Dictionary<string, object> _methodResponses = new(); protected override object Invoke(MethodInfo targetMethod, object[] args) { if (_methodResponses.TryGetValue(targetMethod.Name, out var value)) { return value; } throw new Exception($"No response set up for method {targetMethod.

Devamı 


Basit Bir Mock Framework Geliştirelim 1

2023-05-11 | #diy-mocking-framework #do-it-yourself #mock #net #reflection

Mocklama, testlerinizde belirli sınıfların veya metodların davranışlarını taklit etmek için kullanılır. Örneğin, bir veritabanı çağrısı yapmak yerine, bir mock veritabanı çağrısını simüle edebilirsiniz. Bu, testlerin daha hızlı çalışmasını sağlar ve testlerin bağımlılıklarını azaltır. .NET’de birçok popüler mock kütüphanesi varken neden böyle bir şey yapalım ki. Sadece nasıl çalıştığını anlamak ve biraz pratik yapmak. Ve başlayalım using System; using System.Collections.Generic; public interface IMock<T> { void When(Func<T, bool> predicate); void ThenReturn(object response); } public class Mock<T> : IMock<T> { private Dictionary<Func<T, bool>, object> responses = new(); public void When(Func<T, bool> predicate) { if (!

Devamı 


Basit Bir Test Framework Gelistirelim 15

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Testlerin belirli bir süre sınırlamasına tabi olması önemlidir. Bazı testlerin beklenenden daha uzun sürmesi veya sonsuz bir döngüye girmesi durumunda, süre sınırlaması olan bir test, bu tür sorunları belirlemeyi ve test sürecini düzgün bir şekilde yönetmeyi kolaylaştırır. Her test için bir süre sınırlaması ayarlamak için TestRunner‘ı güncelleyelim: using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Diagnostics; // ... public static class TestRunner { // ... private static async Task<(bool, string)> RunTestMethodAsync<T>(T testClassInstance, MethodInfo testMethod, object[] parameters = null) { try { var stopwatch = Stopwatch.

Devamı 


Basit Bir Test Framework Gelistirelim 14

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Test raporlama, testlerin sonuçlarını görselleştirmek ve anlamak için önemlidir. Testlerin sonuçlarını almak ve bunları daha anlamlı bir formatta raporlamak için bir özellik ekleyebiliriz. Basit bir test raporlama özelliği, testlerin adlarını, testlerin ne kadar sürede tamamlandığını ve hangi testlerin başarılı olduğunu veya başarısız olduğunu içerebilir. TestRunner‘ı geliştirelim: using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Diagnostics; // ... public static class TestRunner { // ... private static async Task<(bool, string)> RunTestMethodAsync<T>(T testClassInstance, MethodInfo testMethod, object[] parameters = null) { try { var stopwatch = Stopwatch.

Devamı 


Basit Bir Test Framework Gelistirelim 13

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Testlerin birbirinden izole olması önemlidir, çünkü bir testin durumu başka bir testi etkilememelidir. Bunun için, her bir test metodu çalıştırıldığında, test sınıfının yeni bir örneğini oluşturabiliriz. Bu, her bir testin kendi durumunu korumasını sağlar ve testler arasında durum paylaşımını önler. Aşağıda, bu özelliği eklemek için TestRunner‘ı güncelleyelim: using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; // ... public static class TestRunner { // ... public static async Task RunTestsAsync<T>(string suiteName = null) { var testMethods = typeof(T) .

Devamı 


Basit Bir Test Framework Geliştirelim 12

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Özellikle I/O yoğun işlemler veya işlemlerin paralel olarak yürütülmesi gereken durumlar için önemlidir. Asenkron testler, testlerin tamamlanmasını beklemek için Task veya Task<T> döndürürler. Örneğin, bir HTTP isteği gönderme veya bir veritabanı sorgusu çalıştırma gibi bir işlemi test etmek isteyebilirsiniz. Bu tür işlemler genellikle asenkron olarak gerçekleştirilir, çünkü bu işlemler genellikle bloklama yapar ve programın diğer işlemlerini engeller. Asenkron test desteğini eklemek için, TestRunner‘ın asenkron test metotlarını tanıyabilmesi ve doğru bir şekilde çalıştırabilmesi gerekir.

Devamı 


Basit Bir Test Framework Geliştirelim 11

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Testlerin daha iyi organize edilmesine ve belirli test gruplarının seçilerek çalıştırılabilmesini istesek ne yaparız. Testleri belirli grup veya kategori halinde düzenlesek? Bu özelliği eklemek için, bir TestSuiteAttribute oluşturabiliriz. Bu attribute, bir test sınıfına veya test metoduna uygulanabilir. Ayrıca, TestRunner‘ı güncelleyerek, belirli bir test grubu için testleri çalıştırabiliriz. using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; // ... public class TestSuiteAttribute : Attribute { public string SuiteName { get; } public TestSuiteAttribute(string suiteName) { SuiteName = suiteName; } } public static class TestRunner { // .

Devamı 


Basit Bir Test Framework Geliştirelim 10

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Genellikle bir test framework’ünde “Parameterized Tests” veya “Data-Driven Tests” adı verilen bir özellik kullanılır. Bu özellik, bir test metodunun farklı veri setleriyle birden çok kez çalıştırılmasını sağlar. Bizde bu özelliği ekleyelim. Aşağıda, TestCase adında bir attribute ve TestRunner‘da bu attribute’u işleyecek kodu tanımlayalım, bu sayede TestRunner ıda refactor edelim. using System; using System.Reflection; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; // ... public class TestCaseAttribute : Attribute { public object[] Parameters { get; } public TestCaseAttribute(params object[] parameters) { Parameters = parameters; } } public static class TestRunner { public static async Task RunTestsAsync<T>() { var testClassInstance = Activator.

Devamı 


Basit Bir Test Framework Geliştirelim 9

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Assert sınıfına HasElements işlevini ekleyelim. Bu işlev, bir koleksiyonun belirli öğelere sahip olup olmadığını kontrol eder. using System; using System.Collections.Generic; using System.Linq; using System.Threading; // ... önceki exception sınıfları ... public class AssertHasElementsFailedException : AssertFailedException { public AssertHasElementsFailedException(IEnumerable<object> missingElements) : base($"Expected collection to contain {string.Join(", ", missingElements)}, but it did not.") { } } public static class Assert { // ... önceki metodlar ... public static void HasElements<T>(IEnumerable<T> collection, params T[] elements) { var missingElements = elements.

Devamı 


Basit Bir Test Framework Geliştirelim 8

2023-05-11 | #diy-unittest-framework #do-it-yourself #net #reflection #unit-test

Şimdi, IsSameAs ve IsNotSameAs işlevlerini ekleyelim. Bu işlevler, iki nesnenin aynı referansa sahip olup olmadığını kontrol eder. using System; using System.Collections.Generic; using System.Linq; using System.Threading; // ... önceki exception sınıfları ... public class AssertIsSameAsFailedException : AssertFailedException { public AssertIsSameAsFailedException(object value, object other) : base($"Expected {value} to be the same as {other}, but it was not.") { } } public class AssertIsNotSameAsFailedException : AssertFailedException { public AssertIsNotSameAsFailedException(object value, object other) : base($"Expected {value} to not be the same as {other}, but it was.

Devamı 