لماذا "الاختبارات الوحدوية فقط" لم تعد كافية؟
\n\nلقد كتبت كود C++ مثاليًا. تمت عملية التجميع بنجاح، الاختبارات الوحدوية خضراء، وتمت الموافقة على مراجعة الكود. تقوم بإصدار الإصدار - وبعد ساعة يشتكي المستخدمون: "الزر لا يعمل"، "قاعدة البيانات لا تستجيب"، "واجهة المستخدم تتجمد". هل هذا مألوف؟
\n\nالمشكلة هي أن الاختبارات الوحدوية تتحقق من الدالة، ولكنها لا تتحقق من السيناريو. إنها معزولة. بينما في العالم الحقيقي، يتفاعل كود C++ الخاص بك مع الشبكة، ونظام الملفات، ووحدة معالجة الرسومات، وواجهات برمجة التطبيقات الخارجية، والخيوط الأخرى. وهنا يأتي دور اختبار E2E لتطبيقات C++ (اختبار شامل).
\n\nفي هذه المقالة، سنشرح كيفية تحويل فوضى أخطاء التكامل إلى نظام منظم من الفحوصات الآلية. ستتعرف على الأدوات التي تعمل حقًا، وكيفية كتابة اختبارات لا تنهار عند التشغيل الأول، وكيفية دمج E2E في خط أنابيب CI/CD. هيا بنا!
\n\nما هو اختبار E2E في سياق C++؟
\n\nاختبار E2E هو التحقق من السيناريو الكامل للمستخدم "من البداية إلى النهاية". على عكس الاختبارات الوحدوية التي تتحقق من دالة منفردة، يقوم اختبار E2E بتشغيل تطبيقك (أو الجزء الحرج منه) في بيئة أقرب ما يمكن إلى بيئة الإنتاج.
\n\nبالنسبة لـ C++، قد يعني هذا:
\n- \n
- تطبيق سطح مكتب: تشغيل نافذة، النقر على زر "إرسال"، التحقق من أن البيانات قد أُرسلت إلى قاعدة البيانات. \n
- تطبيق خادم: إرسال طلب HTTP إلى REST API الخاص بك، التحقق من الرد وحالة قاعدة البيانات. \n
- برامج مضمنة/برمجيات: إرسال إشارة إلى المدخل، التحقق من إشارة الخرج بعد وقت محدد. \n
الفرق الرئيسي هو البيئة الحقيقية. لا توجد كائنات وهمية (mock) لقاعدة البيانات أو الشبكة. فقط أجهزة حقيقية (أو Docker).
\n\nالأدوات: ما الذي يعمل حقًا مع C++ في 2024؟
\n\nدعنا نصل إلى صلب الموضوع. إليك المجموعة التي نستخدمها في العمل:
\n\n- \n
- Catch2 أو Google Test - لكتابة هيكل الاختبارات (ترتيب-تنفيذ-تحقق). \n
- Docker - لرفع بيئة نظيفة (قواعد بيانات، قوائم انتظار، تبعيات). \n
- Pytest + subprocess - للتنسيق (نعم، Python، لكنه مثالي لربط ملفات C++ الثنائية). \n
- Selenium/Appium - إذا كان لديك واجهة مستخدم رسومية على Qt أو WebView. \n
- CMake + CTest - لتشغيل الاختبارات وجمع النتائج. \n
لا تحاول كتابة اختبارات E2E بلغة C++ فقط. هذا مؤلم. استخدم Python كغراء - فهو أسرع للسيناريوهات التكاملية.
\n\nالتطبيق العملي: كتابة اختبار E2E لـ REST API بلغة C++
\n\nلنفترض أن لدينا خادم C++ على cpp-httplib (أو crow، أو drogon). يستقبل طلبات POST على العنوان /api/user ويحفظ المستخدم في PostgreSQL.
سنكتب اختبار E2E يقوم بما يلي:
\n- \n
- رفع حاوية Docker مع PostgreSQL. \n
- تجميع وتشغيل الخادم الخاص بنا. \n
- إرسال طلب HTTP عبر curl (أو عميل C++). \n
- التحقق من ظهور المستخدم في قاعدة البيانات. \n
الخطوة 1: Docker-compose لبيئة الاختبار
\n\nversion: '3.8'\nservices:\n db:\n image: postgres:15\n environment:\n POSTGRES_DB: testdb\n POSTGRES_USER: testuser\n POSTGRES_PASSWORD: testpass\n ports:\n - "5432:5432"\n app:\n build: .\n depends_on:\n - db\n ports:\n - "8080:8080"\n environment:\n DB_HOST: db\n\n\nالخطوة 2: اختبار بلغة C++ باستخدام Catch2
\n\n// test_e2e_api.cpp\n#include <catch2/catch_test_macros.hpp>\n#include <httplib.h>\n#include <nlohmann/json.hpp>\n#include <cstdlib>\n\nTEST_CASE("E2E: Create user via API and verify in DB") {\n // Arrange\n httplib::Client cli("localhost", 8080);\n nlohmann::json user = {\n {"name", "John Doe"}