لماذا لا تكفي اختبارات الوحدة التقليدية؟ وما هو اختبار E2E؟
\n\nتخيل: لقد كتبت كودًا مثاليًا. اختبارات الوحدة كلها ناجحة، التغطية 90%، البنية التحتية رائعة. تنشر الإصدار الجديد... ويشتكي المستخدمون من أن زر "الدفع" لا يعمل، رغم أن جميع البيانات في قاعدة البيانات صحيحة. هل هذا الألم مألوف لك؟
\n\nالمشكلة أن اختبارات الوحدة تختبر أجزاءً معزولة من الكود. لا ترى كيف يتفاعل كود PHP الخاص بك مع مدقق JavaScript في الواجهة الأمامية، وكيف تنتقل الجلسة عبر الكوكيز، وماذا يحدث عندما يتعطل Redis فجأة. هنا يأتي دور اختبار E2E (End-to-End) أو ما يُعرف بالاختبار الشامل.
\n\nاختبارات E2E تحاكي سلوك المستخدم الحقيقي: تنقر على الأزرار، تملأ النماذج، تتحقق من عمليات إعادة التوجيه واستجابات API. في عالم PHP، هذا مهم بشكل خاص لأن التطبيق النموذجي هو شبكة معقدة من Laravel/Symfony وقواعد البيانات وقوائم الانتظار والخدمات الخارجية. بدون E2E، أنت معرض لخطر تفويت أخطاء قد تدمر تجربة المستخدم.
\n\nأدوات اختبار E2E لمشاريع PHP
\n\nفي نظام PHP البيئي، هناك لاعبان رئيسيان. لن أطيل عليك:
\n\n- \n
- Codeception — الإطار الأكثر شيوعًا الذي يجمع اختبارات الوحدة والوظيفية وE2E. يدعم بشكل افتراضي Selenium WebDriver وPHPBrowser وREST API. \n
- PHPUnit + Selenium WebDriver — مجموعة كلاسيكية حيث PHPUnit مسؤول عن التشغيل وSelenium عن محاكاة المتصفح. يتطلب إعدادًا يدويًا أكثر ولكنه يمنحك تحكمًا كاملاً. \n
شخصيًا، أوصي بـ Codeception للبدء: فهو متوافق مع أنظمة إدارة المحتوى الشهيرة (WordPress, Drupal) والأطر (Laravel, Yii2)، ويستغرق الإعداد 10 دقائق فقط.
\n\nتثبيت Codeception لاختبار E2E
\n\nأنشئ ملف composer.json في جذر المشروع (إذا لم يكن موجودًا) ونفّذ الأمر التالي:
composer require --dev codeception/codeception codeception/module-webdriver codeception/module-phpbrowser\n\nثم قم بتهيئة الإطار:
\n\nvendor/bin/codecept init\n\nسيُطلب منك اختيار نوع الاختبارات. اختر Acceptance (E2E). بعد ذلك، سيظهر مجلد tests/acceptance وملف الإعدادات codeception.yml.
كتابة أول اختبار E2E: تسجيل مستخدم جديد
\n\nالسيناريو الأكثر شيوعًا هو التسجيل. دعنا نتحقق من أن النموذج يعمل بشكل صحيح وأن المستخدم يرى رسالة ترحيب بعد الإرسال.
\n\nإعدادات العمل مع المتصفح
\n\nافتح ملف tests/acceptance.suite.yml وقم بتكوين وحدة WebDriver (لمتصفح Chrome):
actor: AcceptanceTester\nmodules:\n enabled:\n - WebDriver:\n url: 'http://localhost:8000' # رابط الخادم المحلي الخاص بك\n browser: chrome\n window_size: 1920x1080\n capabilities:\n chromeOptions:\n args: ["--headless", "--no-sandbox"] # وضع بدون واجهة لـ CI\n - Db:\n dsn: 'mysql:host=localhost;dbname=testdb'\n user: 'root'\n password: ''\n populate: true\n cleanup: true\n\n\nهام: لا تنسَ تشغيل Selenium Server (أو ChromeDriver) في نافذة طرفية منفصلة:
\n\njava -jar selenium-server-standalone.jar\n\nكود الاختبار
\n\nأنشئ ملف tests/acceptance/RegistrationCest.php:
<?php\nuse Codeception\\Util\\Locator;\n\nclass RegistrationCest\n{\n public function _before(AcceptanceTester $I)\n {\n $I->amOnPage('/register');\n }\n\n public function testSuccessfulRegistration(AcceptanceTester $I)\n {\n // 1. نملأ النموذج\n $I->fillField('input[name="name"]', 'أحمد علي');\n $I->fillField('input[name="email"]', 'ahmed@example.com');\n $I->fillField('input[name="password"]', 'StrongPass123!');\n \n