اختبار C++: الوحدة، التكامل، e2e من الألف إلى الياء — دليل كامل

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

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

ابدأ الدورة

مقدمة: لماذا يعتبر اختبار C++ أساس الكود الموثوق

\n

التطوير بلغة C++ دائمًا ما يكون عملًا بمسؤولية عالية. تمنحك اللغة تحكمًا كاملاً في الذاكرة والأداء، لكن ثمن الخطأ قد يكون كارثيًا: من تسرب الذاكرة إلى انهيار النظام بأكمله. ولهذا السبب، فإن اختبار C++ ليس خيارًا، بل مرحلة إلزامية في تطوير أي مشروع جاد.

\n

في هذه المقالة، سنستعرض ثلاثة مستويات رئيسية للاختبار: الوحدة (unit)، التكامل (integration)، وe2e (الشامل). ستتعرف على الفروق بينها، والأدوات التي يجب استخدامها، وكيفية كتابة اختبارات C++ بشكل صحيح. ستكون المادة مفيدة لكل من المبتدئين والمطورين ذوي الخبرة الذين يرغبون في تنظيم معرفتهم.

\n\n

1. اختبار الوحدة في C++: اختبار "اللبنات" الأساسية للبرنامج

\n

اختبارات الوحدة (أو الاختبارات النمطية) تختبر أصغر وحدة في الكود — عادةً دالة فردية أو طريقة في كلاس. هدفها الرئيسي: عزل المكون والتأكد من أنه يعمل بشكل صحيح بمعزل عن التبعيات الخارجية.

\n\n

1.1. أدوات اختبار الوحدة في C++

\n

في سوق C++، توجد عدة أطر ناضجة. إليك الأكثر شيوعًا:

\n
    \n
  • Google Test (GTest) — المعيار الفعلي. ماكرو قوي، دعم للاختبارات المعلمية، وكائنات وهمية (عبر Google Mock).
  • \n
  • Catch2 — خفيف، حديث، مع بناء جملة ممتاز. مناسب للمشاريع الصغيرة.
  • \n
  • Boost.Test — جزء من مكتبة Boost. ضخم ولكنه غني بالوظائف.
  • \n
\n

سنستخدم Google Test باعتباره الخيار الأكثر شيوعًا.

\n\n

1.2. مثال على اختبار وحدة في C++ (Google Test)

\n

لنفترض أن لدينا دالة بسيطة لحساب المضروب:

\n
// math_utils.h\n#pragma once\nint factorial(int n);
\n
// math_utils.cpp\n#include "math_utils.h"\nint factorial(int n) {\n    if (n < 0) return -1; // خطأ: رقم سالب\n    if (n == 0) return 1;\n    return n * factorial(n - 1);\n}
\n

الآن سنكتب اختبار وحدة باستخدام Google Test:

\n
// test_math_utils.cpp\n#include <gtest/gtest.h>\n#include "math_utils.h"\n\nTEST(FactorialTest, HandlesZeroInput) {\n    EXPECT_EQ(factorial(0), 1);\n}\n\nTEST(FactorialTest, HandlesPositiveInput) {\n    EXPECT_EQ(factorial(5), 120);\n}\n\nTEST(FactorialTest, HandlesNegativeInput) {\n    EXPECT_EQ(factorial(-1), -1);\n}\n\nint main(int argc, char **argv) {\n    ::testing::InitGoogleTest(&argc, argv);\n    return RUN_ALL_TESTS();\n}
\n

نشغل الاختبارات — ونرى الضوء الأخضر. إذا كان هناك خطأ في الدالة (مثلاً، factorial(5) يُرجع 119)، سيفشل الاختبار وسنعرف بالمشكلة فورًا.

\n\n

1.3. أفضل الممارسات لاختبارات الوحدة

\n
    \n
  • العزل: استخدم الكائنات الوهمية (Mock) لاستبدال التبعيات الخارجية (قاعدة بيانات، شبكة، نظام ملفات).
  • \n
  • فحص واحد لكل اختبار: يجب أن يختبر كل TEST سلوكًا واحدًا.
  • \n
  • أسماء واضحة: HandlesZeroInput أفضل من Test1.
  • \n
  • تغطية الحالات الحدية: الصفر، الأرقام السالبة، القيم القصوى.
  • \n
\n\n

2. اختبار التكامل (Integration Testing): التحقق من التفاعل

\n

تختبر اختبارات التكامل كيفية عمل الوحدات المختلفة للنظام معًا. على عكس اختبارات الوحدة، لا نقوم بعزل المكونات هنا — بل نتحقق من الروابط الحقيقية (مثل استدعاء دالة من كلاس يستخدم كلاسًا آخر).

\n\n

2.1. متى نحتاج إلى اختبار التكامل؟

\n