كائنات Mock والـ Fixtures في اختبارات PHP: كيف لا تصاب بالجنون عند كتابة اختبارات الوحدة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

لماذا الاختبارات بدون كائنات وهمية مثل الطهي بدون ملح

\n\n

تخيل أنك تكتب تطبيقًا يرسل إشعارات البريد الإلكتروني، ويعمل مع قاعدة البيانات، ويتصل بـ API خارجي. كيف ستختبر هذا بدون كائنات وهمية وبيانات اختبارية في PHP؟ ستضطر كل مرة لإرسال رسائل حقيقية، وإنشاء سجلات اختبارية في قاعدة البيانات، وانتظار رد من الخدمة الخارجية. هذا بطيء، غير موثوق، وببساطة غير ذكي.

\n\n

هنا تأتي بدائل الاختبار لإنقاذك — بدائل للكائنات الحقيقية. في نظام PHP البيئي، نستخدم مزيجًا من: كائنات وهمية (mock) للتحقق من التفاعلات و بيانات اختبارية (fixtures) لإعداد البيانات. دعنا نفهم كيف يعمل هذا عمليًا.

\n\n

Mock vs Stub vs Fake: لا تخلط بينهم

\n\n

قبل الغوص في الكود، دعنا نضع النقاط على الحروف. في عالم اختبارات الوحدة في PHP، هناك ثلاثة أنواع رئيسية من البدائل:

\n\n
    \n
  • دعامة (Stub) — يعيد بيانات محددة مسبقًا. تتحقق من أن كودك يعالج هذه البيانات بشكل صحيح.
  • \n
  • محاكاة (Mock) — لا يعيد البيانات فقط، بل يتحقق أيضًا من كيفية استدعاء النظام للطرق: كم مرة، بأي وسائط، وبأي ترتيب.
  • \n
  • مزيف (Fake) — تنفيذ عملي مبسط (مثل قاعدة بيانات في الذاكرة).
  • \n
\n\n

في PHPUnit، وهو المعيار الفعلي لـ اختبارات PHP، غالبًا ما يتم الخلط بين هذه المفاهيم. لكننا سنكون دقيقين: الكائنات الوهمية في PHP هي تلك التي تحدد فيها التوقعات (expectations).

\n\n

كتابة أول كائن وهمي باستخدام PHPUnit

\n\n

لنفترض أن لدينا كلاس Mailer يرسل رسائل البريد الإلكتروني. نريد التحقق من أن خدمة التسجيل تستدعي الطريقة send() مرة واحدة بالضبط مع البيانات الصحيحة.

\n\n
<?php\nuse PHPUnit\\Framework\\TestCase;\n\nclass UserRegistrationTest extends TestCase\n{\n    public function testSendWelcomeEmailOnRegistration(): void\n    {\n        // إنشاء كائن وهمي لـ Mailer\n        $mailer = $this->createMock(Mailer::class);\n        \n        // إعداد التوقع: سيتم استدعاء send مرة واحدة\n        $mailer->expects($this->once())\n               ->method('send')\n               ->with(\n                   $this->equalTo('user@example.com'),\n                   $this->stringContains('Welcome')\n               );\n        \n        $service = new UserRegistrationService($mailer);\n        $service->register('user@example.com', 'password123');\n    }\n}\n
\n\n

لاحظ: نحن لا نتحقق من أن الرسالة أُرسلت فعليًا. نحن نتحقق من أن كودنا حاول إرسالها — وهذا هو جوهر الكائنات الوهمية في اختبارات PHP. إذا لم يتم استدعاء الطريقة send() (أو تم استدعاؤها مرتين)، سيفشل الاختبار.

\n\n

طريقة expects وإمكانياتها

\n\n

يوفر PHPUnit واجهة برمجة تطبيقات غنية لإعداد التوقعات:

\n\n
    \n
  • $this->once() — استدعاء واحد بالضبط
  • \n
  • $this->exactly(3) — ثلاثة استدعاءات بالضبط
  • \n
  • $this->atLeastOnce() — استدعاء واحد على الأقل
  • \n
  • $this->never() — لا يجب استدعاء الطريقة أبدًا
  • \n
\n\n

بالنسبة للوسائط، استخدم المطابقات (constraints):

\n\n
$mailer->expects($this->once())\n       ->method('send')\n       ->with(\n           $this->callback(function($email) {\n               return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;\n           }),\n           $this->anything() // لا نهتم بالوسيط الثاني\n       );\n
\n\n

البيانات الاختبارية في PHP: إعداد البيانات قبل أن تحتاجها

\n\n

البيانات الاختبارية (Fixtures) هي حالة بيانات محددة مسبقًا يكون فيها النظام قبل تنفيذ الاختبار. في PHPUnit، نستخدم الطريقتين setUp() و

المدونات

توصيات الكتب