مقدمة: لماذا نحتاج الاختبار في C#؟
\nفي التطوير الحديث باستخدام C# (.NET)، جودة الكود ليست رفاهية، بل ضرورة. لا يقتصر الاختبار على اكتشاف الأخطاء قبل الوصول إلى الإنتاج فحسب، بل يعمل أيضًا كتوثيق حي، ويسرّع عملية إعادة الهيكلة. هناك ثلاثة مستويات رئيسية للاختبار تشكل "هرم الاختبارات": Unit (الوحدة)، Integration (التكامل)، وE2E (الشامل). في هذه المقالة، سنشرح كل مستوى منها مع أمثلة من كود C# حقيقي.
\n\n1. اختبار الوحدة: أساس الجودة
\nتختبر اختبارات الوحدة جزءًا معزولًا من الكود (دالة، كلاس) بعيدًا عن التبعيات الخارجية (قواعد البيانات، نظام الملفات، API). في بيئة .NET، هناك ثلاثة أطر عمل شائعة: xUnit (موصى به للمشاريع الجديدة)، NUnit، وMSTest.
\n\nالمبادئ الأساسية (FIRST)
\n- \n
- Fast — سريعة (بالميلي ثانية). \n
- Isolated — معزولة (نستخدم الكائنات الوهمية). \n
- Repeatable — قابلة للتكرار. \n
- Self-validating — ذاتية التحقق (Assert). \n
- Timely — في الوقت المناسب. \n
مثال لاختبار وحدة باستخدام xUnit وMoq
\nلنفترض أن لدينا خدمة لحساب الخصم:
\npublic interface IDiscountService\n{\n decimal CalculateDiscount(decimal price, bool isLoyaltyMember);\n}\n\npublic class DiscountService : IDiscountService\n{\n public decimal CalculateDiscount(decimal price, bool isLoyaltyMember)\n {\n if (isLoyaltyMember) return price * 0.9m; // خصم 10%\n return price;\n }\n}\nاختبار باستخدام Moq (لمحاكاة التبعيات) وxUnit:
\nusing Xunit;\nusing Moq;\n\npublic class DiscountServiceTests\n{\n [Fact]\n public void CalculateDiscount_WhenLoyaltyMember_ReturnsDiscountedPrice()\n {\n // ترتيب\n var service = new DiscountService();\n var price = 100m;\n\n // تنفيذ\n var result = service.CalculateDiscount(price, true);\n\n // تأكيد\n Assert.Equal(90m, result);\n }\n\n [Theory]\n [InlineData(100, false, 100)]\n [InlineData(200, true, 180)]\n public void CalculateDiscount_MultipleCases_ReturnsCorrectValues(decimal price, bool isLoyalty, decimal expected)\n {\n var service = new DiscountService();\n var result = service.CalculateDiscount(price, isLoyalty);\n Assert.Equal(expected, result);\n }\n}\nنصيحة: استخدم السمة [Fact] للاختبارات الفردية و[Theory] + [InlineData] للاختبارات المعلمة.
2. اختبار التكامل: التحقق من ترابط المكونات
\nتتحقق اختبارات التكامل من كيفية عمل عدة وحدات معًا - على سبيل المثال، وحدة التحكم، الخدمة، وقاعدة بيانات حقيقية (أو بديل لها، مثل SQLite في الذاكرة). في ASP.NET Core، يُستخدم WebApplicationFactory لهذا الغرض.
إعداد WebApplicationFactory
\nلننشئ كلاس اختبار يقوم بتشغيل مضيف ويب اختباري:
\nusing Microsoft.AspNetCore.Mvc.Testing;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing MyApp.Data;\n\npublic class CustomWebApplicationFactory : WebApplicationFactory<Program>\n{\n protected override void ConfigureWebHost(IWebHostBuilder builder)\n {\n builder.ConfigureServices(services =>\n {\n // إزالة DbContext الحقيقي\n var descriptor = services.SingleOrDefault(\n d => d.ServiceType == typeof(DbContextOptions<AppDbContext>));\n if (descriptor != null) services.Remove(descriptor);\n\n // إضافة قاعدة بيانات في الذاكرة\n services.AddDbContext<AppDbContext>(options =>\n