ما هو Moq ولماذا هو مطلوب؟
\n\nMoq (تُنطق "موك") هي مكتبة شائعة لإنشاء كائنات mock (كائنات وهمية) في C# (.NET). وهي جزء من نظام الاختبارات الوحدوية وتُستخدم لعزل الكود المختبر عن تبعياته.
\n\nفي التطبيقات الحقيقية، غالبًا ما تعتمد الفئات على فئات أخرى: قواعد البيانات، خدمات الويب، نظام الملفات، API لخدمات الطرف الثالث. عند كتابة اختبارات وحدوية، لا نريد اختبار هذه التبعيات الخارجية — بل نريد فقط التحقق من منطق الفئة الخاصة بنا. يسمح Moq بإنشاء كائنات "مزيفة" (mock) تحاكي سلوك التبعيات الحقيقية، ولكنها تحت السيطرة الكاملة للاختبار.
\n\nسيناريوهات الاستخدام الرئيسية لـ Moq:
\n- \n
- عزل الاختبارات: اختبار فئة واحدة دون تشغيل قاعدة بيانات أو خدمات خارجية. \n
- التحقق من التفاعلات: التأكد من استدعاء طريقة بالوسائط الصحيحة، وعدد معين من المرات. \n
- تعيين القيم المُرجعة: جعل التبعية تُرجع البيانات المطلوبة للتحقق من المنطق. \n
- محاكاة الاستثناءات: التحقق من كيفية معالجة الكود للأخطاء من الأنظمة الخارجية. \n
يعمل Moq مع الواجهات والطرق الافتراضية للفئات. هذا هو القيد الرئيسي: لا يمكنك عمل mock لطريقة ثابتة أو طريقة غير افتراضية.
\n\nتثبيت Moq
\n\nيتم توزيع Moq عبر NuGet — مدير الحزم لـ .NET. يمكن تثبيته بعدة طرق:
\n\nعبر .NET CLI (موصى به)
\ndotnet add package Moq\n\nعبر Package Manager Console (Visual Studio)
\nInstall-Package Moq\n\nعبر واجهة NuGet Package Manager UI
\nفي Visual Studio: انقر بزر الماوس الأيمن على المشروع → Manage NuGet Packages → ابحث عن "Moq" → تثبيت
\n\nالمتطلبات: .NET Framework 4.5+ أو .NET Core 2.0+ / .NET 5+
\n\nبداية سريعة: أول اختبار مع Moq
\n\nلنفترض أن لدينا واجهة مستودع وخدمة تستخدمها:
\n\npublic interface IUserRepository\n{\n User GetUserById(int id);\n void SaveUser(User user);\n}\n\npublic class UserService\n{\n private readonly IUserRepository _repository;\n\n public UserService(IUserRepository repository)\n {\n _repository = repository;\n }\n\n public string GetUserName(int userId)\n {\n var user = _repository.GetUserById(userId);\n return user?.Name ?? "Unknown";\n }\n}\n\npublic class User\n{\n public int Id { get; set; }\n public string Name { get; set; }\n}\n\nالآن سنكتب اختبارًا باستخدام Moq:
\n\nusing Moq;\nusing Xunit;\n\npublic class UserServiceTests\n{\n [Fact]\n public void GetUserName_WhenUserExists_ReturnsUserName()\n {\n // Arrange\n var mockRepo = new Mock<IUserRepository>();\n mockRepo.Setup(repo => repo.GetUserById(1))\n .Returns(new User { Id = 1, Name = "Alice" });\n\n var service = new UserService(mockRepo.Object);\n\n // Act\n var result = service.GetUserName(1);\n\n // Assert\n Assert.Equal("Alice", result);\n mockRepo.Verify(repo => repo.GetUserById(1), Times.Once);\n }\n}\n\nتحليل المثال:
\n- \n
new Mock<IUserRepository>()— إنشاء كائن mock للواجهة. \n .Setup(...)— تكوين السلوك: عند استدعاءGetUserById(1)، إرجاع المستخدم Alice. \n mockRepo.Object— الحصول على الكائن "المزيف" الذي نمرره إلى الخدمة. \n mockRepo.Verify(...)— التحقق من أن الطريقة تم استدعاؤها مرة واحدة بالضبط. \n
الطرق والوظائف الأساسية لـ Moq
\n\n1. Mock<T>.Setup()
\nما يفعله: يكوّن سلوك الط