مقدمة: لماذا نكتب الأخطاء ثم نصلحها ببطولة؟
\n\nهل سبق لك أن كتبت كودًا "يعمل بشكل طبيعي نوعًا ما"، ثم بعد ثلاثة أيام وجدت خطأً تسبب في انهيار كل شيء؟ إذا كان الأمر كذلك - مرحبًا بك في النادي. إذا لم يكن كذلك - فأنت إما إله C++، أو ببساطة لم تقم بتشغيل الإنتاج بعد.
\n\nالتطوير عبر الاختبارات (TDD) ليس حمية عصرية للمبرمجين. إنه انضباط يقلب عملية كتابة الكود رأسًا على عقب. بدلاً من كتابة المنطق أولاً ثم التفكير بشكل محموم في كيفية اختباره، نفعل العكس: الاختبار أولاً، ثم الكود. يبدو هذا جنونيًا؟ ربما. ولكن هكذا يولد الكود الذي لا تخجل من عرضه على زملائك والذي لا يتعطل مساء الجمعة.
\n\nفي هذه المقالة، سنشرح TDD في C++ بأمثلة حقيقية: سنكتب مكتبة بسيطة للعمل مع أرقام فيبوناتشي باستخدام دورة Red-Green-Refactor. سترى كيف يساعد TDD ليس فقط في تجنب الأخطاء، ولكن أيضًا في تصميم الواجهات.
\n\nما هو TDD ولماذا C++ بدونه مثل سيارة بدون فرامل؟
\n\nTDD (Test-Driven Development) هي منهجية تطوير يتم فيها كتابة اختبار يفشل مسبقًا أولاً (Red)، ثم كتابة الحد الأدنى من الكود الذي يجعل الاختبار ينجح (Green)، وأخيرًا إجراء إعادة هيكلة (Refactor) لتحسين الهيكل دون تغيير السلوك.
\n\nلماذا هذا مهم بشكل خاص لـ C++؟ لأن C++ هي لغة يسهل فيها إطلاق النار على قدمك: سلوك غير محدد، تسرب الذاكرة، تحويلات غير صحيحة للأنواع. TDD ينشئ تلقائيًا شبكة أمان تلتقط الأخطاء في مرحلتي التجميع والتنفيذ.
\n\nدورة Red-Green-Refactor: كيف تعمل
\n\n- \n
- Red: نكتب اختبارًا يجب أن يفشل. هذا هو "المتطلب" الخاص بنا للكود. \n
- Green: نكتب الحد الأدنى من الكود ليجتاز الاختبار. لا هندسة مفرطة! \n
- Refactor: نحسن الكود (نزيل التكرار، نبسط المنطق) - تبقى الاختبارات خضراء. \n
يبدو الأمر بسيطًا؟ نعم. لكنه يتطلب انضباطًا عمليًا. لنجرب.
\n\nأدوات TDD في C++: Google Test مقابل Catch2
\n\nقبل كتابة الكود، دعنا نختار إطار عمل للاختبار. المرشحان الرئيسيان:
\n\n- \n
- Google Test - قوي، شائع، مع الكثير من الماكرو. مناسب تمامًا للمشاريع الكبيرة. \n
- Catch2 - خفيف، حديث، مع بناء جملة مريح. مثالي للأمثلة التعليمية والخدمات المصغرة. \n
في هذه المقالة، سنستخدم Catch2 (v3) لأنه بسيط ولا يتطلب إعدادات إضافية. لكن إذا كنت تفضل Google Test - فمبادئ TDD هي نفسها.
\n\nتطبيق عملي: كتابة TDD لأرقام فيبوناتشي
\n\nلنتخيل أننا بحاجة لكتابة دالة fibonacci(int n) تُرجع رقم فيبوناتشي رقم n (0 = 0، 1 = 1، 2 = 1، 3 = 2، إلخ).
الخطوة 1: Red - نكتب اختبارًا يفشل
\n\nلننشئ ملف test_fib.cpp:
#define CATCH_CONFIG_MAIN\n#include <catch2/catch_test_macros.hpp>\n\n// طالما لم يتم تعريف الدالة - هذا طبيعي\nint fibonacci(int n);\n\nTEST_CASE("أرقام فيبوناتشي", "[fib]") {\n REQUIRE(fibonacci(0) == 0);\n REQUIRE(fibonacci(1) == 1);\n REQUIRE(fibonacci(2) == 1);\n REQUIRE(fibonacci(10) == 55);\n}\n\nنحاول التجميع - نحصل على خطأ في الربط. الاختبار RED. ممتاز!
\n\nالخطوة 2: Green - نكتب الحد الأدنى من الكود ليجتاز الاختبار
\n\nلننشئ ملف fib.cpp:
int fibonacci(int n) {\n if (n <= 1) return n;\n return fibonacci(n - 1) + fibonacci(n - 2);\n}\n\nنجمع ونشغل الاختبارات. هل تنجح؟ نعم، لكن هذا غير فعال. ومع ذلك، هدفنا هو Green، وليس الكمال. نتركه كما هو الآن.
\n\n