التقاط الأخطاء بشكل صحيح: كيفية اختبار الاستثناءات في JUnit في 2025

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

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

ابدأ الدورة

مقدمة: "لماذا يفشل اختباري بينما يجب أن ينجح؟"

\n\n

هل سبق لك أن كتبت اختبار وحدة كان من المفترض أن يلتقط استثناءً، ولكنه بدلاً من ذلك فشل بخطأ أحمر؟ مألوف؟ سؤال "How do you assert that a certain exception is thrown in JUnit tests?" على Stack Overflow حصد آلاف المشاهدات ومئات التعليقات. وهذا ليس من قبيل الصدفة: اختبار الاستثناءات هو أحد تلك المواضيع التي حتى المطورين ذوي الخبرة يتعثرون فيها أحيانًا.

\n\n

في عام 2025، عندما أصبحت جودة الكود عاملاً حاسمًا (خاصة في الخدمات المصغرة وخطوط أنابيب AI)، فإن القدرة على التحقق من الاستثناءات بشكل صحيح ليست مجرد "أخلاق حميدة"، بل كفاءة أساسية. في هذه المقالة، سنحلل جميع الطرق الحالية لتأكيد الاستثناءات في JUnit 5، ونعرض المخاطر الخفية ونقدم قائمة مرجعية لأفضل الممارسات. هيا بنا!

\n\n

لماذا من المهم اختبار الاستثناءات؟

\n\n

تخيل: أنت تكتب طريقة divide(int a, int b). إذا كان b == 0، يجب أن ترمي الطريقة ArithmeticException. بدون اختبار لهذا السلوك، فإنك تخاطر أنه بعد شهر، مطور آخر (أو أنت نفسك) قد يزيل التحقق عن طريق الخطأ، وسيتعطل التطبيق في الإنتاج بخطأ غير مفهوم.

\n\n

اختبارات الاستثناءات هي شبكة الأمان الخاصة بك. إنها توثق السلوك المتوقع للنظام في الحالات الحدودية. و JUnit 5 يوفر عدة أدوات أنيقة لهذا الغرض.

\n\n

الطريقة 1: assertThrows - ملك الاختبار الحديث

\n\n

بدءًا من JUnit 5 (وحزمة org.junit.jupiter.api)، أصبحت طريقة assertThrows المعيار الفعلي. لماذا؟ لأنها موجزة وقابلة للقراءة ووظيفية.

\n\n
import static org.junit.jupiter.api.Assertions.assertThrows;\n\n@Test\nvoid whenDivideByZero_thenArithmeticException() {\n    assertThrows(ArithmeticException.class, \n        () -> calculator.divide(10, 0));\n}\n
\n\n

ماذا يحدث هنا؟ assertThrows تأخذ فئة الاستثناء المتوقع ولامدا مع الكود الذي يجب أن يرمي الاستثناء. إذا تم رمي الاستثناء - يكون الاختبار أخضر. إذا لم يتم - يكون أحمر. كل شيء بسيط وواضح.

\n\n

نسخة موسعة: التحقق من رسالة الاستثناء

\n\n

أحيانًا لا يكفي مجرد التحقق من نوع الاستثناء - تحتاج إلى التأكد من أن الرسالة تحتوي على النص الصحيح. assertThrows تُرجع كائن الاستثناء، ويمكنك التحقق من خصائصه:

\n\n
import static org.junit.jupiter.api.Assertions.*;\n\n@Test\nvoid whenInvalidEmail_thenExceptionWithMessage() {\n    IllegalArgumentException exception = assertThrows(\n        IllegalArgumentException.class,\n        () -> userService.register("invalid-email")\n    );\n    \n    assertTrue(exception.getMessage().contains("Некорректный email"));\n}\n
\n\n

هذا النهج مفيد بشكل خاص عند اختبار الاستثناءات المخصصة ذات الحقول (مثل رمز الخطأ).

\n\n

الطريقة 2: expected القديمة الجيدة (إرث JUnit 4)

\n\n

إذا كنت تعمل مع JUnit 4 أو تدعم كودًا قديمًا، فمن المحتمل أنك صادفت السمة expected في التعليق التوضيحي @Test:

\n\n
@Test(expected = ArithmeticException.class)\npublic void whenDivideByZero_thenException() {\n    calculator.divide(10, 0);\n}\n
\n\n

العيب: هذه الطريقة لا تسمح بالتحقق من رسالة الاستثناء أو خصائصه. بالإضافة إلى ذلك، إذا تم رمي الاستثناء في وقت أبكر مما تتوقع (على سبيل المثال، في سطر التهيئة)، فقد ينجح الاختبار بشكل خاطئ. في عام 2025، نوصي بتجنب هذا النهج في الكود الجديد.

\n\n

الطريقة 3: Try-catch مع علامة (لعشاق التحكم)

\n\n

قبل ظهور JUnit 5، استخدم الكثيرون بناء try-catch مع علامة منطقية. يبدو ضخمًا، لكنه يعطي تحكمًا كاملاً:

\n\n
@Test\nvoid whenDivideByZero_thenExceptionCaught() {\n    boolean thrown = false;\n    try {\n        calculator.divide(10, 0);\n    } catch (Arithmeti                

المدونات

توصيات الكتب