JUnit: ما هو، المفاهيم الأساسية وكيف يعمل

المؤلف: IT Sectr نُشر: 2026-04-08 وقت القراءة: 8 دق

JUnit هو إطار عمل قياسي للاختبارات الوحدوية في بيئة Java وKotlin، يُستخدم في تطوير Android للتحقق من منطق الأعمال على مستوى المكونات المعزولة. يوفر الإطار مجموعة من التعليقات التوضيحية وطرق التأكيد وTest Runner للاكتشاف التلقائي للاختبارات وتنفيذها. وفقًا لـ JUnit.org، تظل المكتبة الحل الأكثر شيوعًا للاختبارات الوحدوية في بيئة JVM: أكثر من 70% من مشاريع Java تستخدم JUnit بأي إصدار.

الرئيسية

  • JUnit هو إطار عمل مفتوح المصدر للاختبارات الوحدوية لرمز Java وKotlin.
  • التعليقات التوضيحية — @Test و@BeforeEach و@BeforeAll تدير دورة حياة فئة الاختبار.
  • التأكيدات — assertEquals وassertTrue وassertThrows تتحقق من نتائج التنفيذ المتوقعة.
  • الاختبارات المعلمة — تسمح بتشغيل اختبار واحد بمجموعات مختلفة من بيانات الإدخال.
  • Test Runner — البنية التحتية لـ JUnit تجد وتشغل جميع الاختبارات في المشروع تلقائيًا.

ما هو JUnit؟

JUnit هو إطار عمل مفتوح المصدر لكتابة وتشغيل اختبارات وحدوية قابلة للتكرار بلغة Java وKotlin. إنه جزء من بيئة xUnit — عائلة من الأطر المبنية على بنية Kent Beck وErich Gamma — وهو أداة الاختبار القياسية في Android Studio وIntelliJ IDEA.

المهمة الرئيسية لـ JUnit هي عزل جزء صغير من الكود (طريقة، فئة) والتحقق من سلوكه في ظروف محكومة. تُكتب الاختبارات كفئات Java/Kotlin عادية مع تعليقات توضيحية، ويتولى الإطار اكتشاف الاختبارات وإدارة دورة حياتها وجمع إحصائيات التنفيذ.

ظهر الإصدار الأول من JUnit في 1997 وغيّر نهج التطوير بشكل جذري من خلال نشر ممارسات التطوير القائم على الاختبار (TDD). اليوم، JUnit 5 (Jupiter) هو الإصدار الحالي، المعاد تصميمه بالكامل ببنية معيارية تدعم Java 8+ والإضافات.

كيف يعمل JUnit

آلية تنفيذ JUnit تستند إلى نمط Test Runner، الذي يمسح classpath، ويجد الطرق ذات التعليق التوضيحي @Test، وينشئ مثيلاً لفئة الاختبار ويشغّل الطرق بترتيب معين. يدير Test Runner دورة الحياة: BeforeAll ← BeforeEach ← Test ← AfterEach ← AfterAll.

دورة حياة فئة الاختبار

يغلف JUnit كل طريقة اختبار في مثيل فئة منفصل، مما يضمن العزل بين الاختبارات. هذا يعني أن حقول الفئة لا تحتفظ بالحالة بين طرق @Test المختلفة — يبدأ كل اختبار بكائن نظيف.

البنية الأساسية للاختبار

أبسط اختبار في JUnit هو طريقة مع التعليق التوضيحي @Test تستدعي الكود قيد الاختبار وتتحقق من النتيجة باستخدام تأكيد. إذا فشل التأكيد، يعتبر الاختبار فاشلاً ويبلغ JUnit عن الخطأ.

java
@Test
void additionShouldReturnCorrectSum() {
    var calculator = new Calculator();
    var result = calculator.add(2, 3);
    assertEquals(5, result);
}

يجد Test Runner تلقائيًا مثل هذه الطريقة، ويشغلها ويبلغ عن النتيجة. إذا لم ترمِ الطريقة استثناءً — ينجح الاختبار (green). إذا فشل التأكيد — يفشل الاختبار (red).

تعليقات JUnit التوضيحية: دورة حياة الاختبار

التعليقات التوضيحية في JUnit تحدد متى وكيف يجب تنفيذ كود الاختبار. في JUnit 5، توجد التعليقات التوضيحية في الحزمة org.junit.jupiter.api وتغطي جميع المراحل: إعداد البيانات، تنفيذ الاختبار، تنظيف الموارد.

التعليق التوضيحيالغرضالتنفيذ
@Testيحدد طريقة اختبارمرة واحدة لكل استدعاء
@BeforeEachالإعداد قبل كل اختبارقبل كل @Test
@BeforeAllتهيئة الفئة لمرة واحدةمرة واحدة قبل جميع الاختبارات
@AfterEachالتنظيف بعد كل اختباربعد كل @Test
@AfterAllإنهاء الفئة لمرة واحدةمرة واحدة بعد جميع الاختبارات
@DisplayNameاسم اختبار قابل للقراءةزخرفة

مثال على استخدام التعليقات التوضيحية

لنفكر في فئة اختبار كاملة مع دورة حياة مناسبة. تنشئ طريقة setUp مثيلاً جديدًا من Calculator قبل كل اختبار، وتحرر tearDown الموارد — على سبيل المثال، إغلاق واصفات الملفات أو اتصالات قاعدة البيانات.

java
class CalculatorTest {

    private Calculator calculator;

    @BeforeEach
    void setUp() {
        calculator = new Calculator();
    }

    @Test
    void subtractionShouldReturnCorrectResult() {
        int result = calculator.subtract(10, 4);
        assertEquals(6, result);
    }

    @AfterEach
    void tearDown() {
        calculator.reset();
    }
}

التأكيدات: التحقق من النتائج في JUnit

التأكيدات هي طرق ثابتة تقارن النتيجة الفعلية بالنتيجة المتوقعة وتطرح استثناءً في حالة عدم التطابق. يوفر JUnit 5 الفئة org.junit.jupiter.api.Assertions مع أكثر من 25 طريقة لسيناريوهات التحقق المختلفة — من مقارنة القيم البسيطة إلى فحوصات المهلة والتأكيدات المجمعة.

  • assertEquals(expected, actual) — يتحقق من المساواة عبر equals().
  • assertTrue(condition) — يتحقق من أن الشرط صحيح.
  • assertFalse(condition) — يتحقق من أن الشرط خاطئ.
  • assertNotNull(object) — يتحقق من أن الكائن ليس null.
  • assertNull(object) — يتحقق من أن الكائن هو null.
  • assertThrows(exception, executable) — يتحقق من أن الكود يطرح استثناءً محددًا.
  • assertAll(executables) — يجمع عدة تأكيدات وينفذها جميعًا دون التوقف عند أول فشل.

assertThrows للتحقق من الاستثناءات

يستحق الأسلوب assertThrows اهتمامًا خاصًا، حيث يسمح بالتحقق من أن الكود يعالج بشكل صحيح حالات الخطأ — القسمة على صفر، تمرير null، تجاوز الحدود.

java
@Test
void divisionByZeroShouldThrowException() {
    Calculator calc = new Calculator();

    ArithmeticException exception = assertThrows(
        ArithmeticException.class,
        () -> calc.divide(10, 0)
    );

    assertEquals("Cannot divide by zero", exception.getMessage());
}

الاختبارات المعلمة في JUnit

الاختبارات المعلمة تسمح بتشغيل نفس طريقة الاختبار بمجموعات مختلفة من الوسائط. في JUnit 5، يتم ذلك باستخدام التعليق التوضيحي @ParameterizedTest مع مصدر بيانات — @ValueSource أو @CsvSource أو @MethodSource أو @EnumSource.

يقلل هذا النهج بشكل جذري من تكرار الكود: بدلاً من عشرة اختبارات متطابقة لقيم مختلفة، يُكتب طريقة واحدة معلمة. وفقًا لـ Google Testing Blog، يقلل التوسيم من حجم كود الاختبار بنسبة 40–60% دون فقدان التغطية.

مثال مع CsvSource

يمرر التعليق التوضيحي @CsvSource صفوفًا متعددة مفصولة بفواصل إلى الاختبار. كل صف يتوافق مع تشغيل اختبار واحد. يقوم JUnit تلقائيًا بتحويل القيم النصية إلى الأنواع المطلوبة: int وlong وString وغيرها.

java
@ParameterizedTest
@CsvSource({
    "1,    1,   2",
    "2,    3,   5",
    "10,  20,  30",
    "-1,   1,   0"
})
void additionWithMultipleInputs(int a, int b, int expected) {
    assertEquals(expected, a + b);
}

MethodSource للكائنات المعقدة

عندما تكون بيانات الإدخال أكثر تعقيدًا من الأرقام أو السلاسل البسيطة، يُستخدم @MethodSource. يشير إلى طريقة ثابتة تعيد Stream من الوسائط — على سبيل المثال، Stream من Arguments أو Stream من كائنات User لاختبار طبقة DAO.

دمج JUnit مع مشاريع Android

في تطوير Android، يُستخدم JUnit جنبًا إلى جنب مع AndroidX Test، الذي يوفر إضافات لاختبار Activity وContent Provider ومكونات Android الأخرى. يتولى JUnit الاختبارات الوحدوية التي تُنفذ على JVM بدون محاكي، بينما يتولى AndroidX Test الاختبارات الآلية على الجهاز.

إعداد Gradle

لإضافة JUnit 5 إلى مشروع Android، يكفي تضمين التبعية org.junit.jupiter:junit-jupiter في build.gradle على مستوى الوحدة. يدعم إضافة AGP لـ Gradle تشغيل اختبارات JUnit 5 على JVM من خلال Test Runner القياسي.

kotlin
// build.gradle.kts
android {
    testOptions {
        unitTests.isIncludeAndroidResources = true
    }
}

dependencies {
    testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
    testImplementation("androidx.test:core-ktx:1.6.1")
}

اختبار ViewModel باستخدام JUnit

في الممارسة العملية، يُستخدم JUnit في أغلب الأحيان لاختبار ViewModel والمستودعات — الطبقات التي لا تتطلب سياق Android أو محاكي. يتم تنفيذ هذا الاختبار في أجزاء من الثانية ويمكن تشغيله مئات المرات دون إضاعة الوقت.

  • ViewModel — التحقق من الحالات: تحميل، نجاح، خطأ.
  • Repository — التحقق من تعيين البيانات ومعالجة الأخطاء.
  • UseCase — التحقق من منطق الأعمال باستخدام نماذج وهمية للتبعيات.

JUnit 4 مقابل JUnit 5: الاختلافات الرئيسية

JUnit 5 (Jupiter) ليس مجرد إصدار جديد، بل هو منصة معاد تصميمها بالكامل مقسمة إلى ثلاث وحدات: JUnit Platform (تنفيذ الاختبارات على JVM)، JUnit Jupiter (API لكتابة الاختبارات)، وJUnit Vintage (التوافق مع الإصدارات السابقة لـ JUnit 4). تسمح هذه المعيارية بتوصيل محركات اختبار مختلفة — على سبيل المثال، Spek لـ Kotlin أو TestNG.

الخاصيةJUnit 4JUnit 5
الحزمةorg.junitorg.junit.jupiter
التعليق التوضيحي الأساسي@Test (من junit.framework)@Test (من org.junit.jupiter.api)
Before/After@Before, @After, @BeforeClass@BeforeEach, @AfterEach, @BeforeAll
المعلمة@RunWith(Parameterized.class)@ParameterizedTest + @ValueSource
الإضافة@Rule, @ClassRule@ExtendWith, API أكثر مرونة
Java minJava 5Java 8+

لا يتطلب الانتقال من JUnit 4 إلى JUnit 5 إعادة كتابة جميع الاختبارات — يكفي إضافة JUnit Vintage Engine وستستمر الاختبارات القديمة في العمل. يُوصى بكتابة الاختبارات الجديدة باستخدام JUnit 5 للاستفادة من الإضافات وتأكيدات lambda والدعم المدمج لـ التوسيم.

الأسئلة المتداولة

كيف يختلف JUnit عن Mockito؟

JUnit هو إطار عمل لكتابة وتشغيل الاختبارات، بينما Mockito مكتبة لإنشاء كائنات وهمية. يتم استخدامهما معًا: يدير JUnit تنفيذ الاختبار، ويستبدل Mockito تبعيات الفئة قيد الاختبار.

هل يمكن استخدام JUnit 5 في مشاريع Android؟

نعم، JUnit 5 متوافق تمامًا مع مشاريع Android. للاختبارات الوحدوية، يكفي إضافة التبعية junit-jupiter في build.gradle. تستمر الاختبارات الآلية في العمل من خلال AndroidX Test Runner.

ما هي المجموعة الدنيا من التعليقات التوضيحية اللازمة للاختبار؟

كحد أدنى، يكفي تعليق توضيحي واحد @Test قبل الطريقة. يُوصى باستخدام @BeforeEach و@AfterEach للتهيئة والتنظيف، لكنهما غير إلزاميين.

ما هو Test Runner في JUnit؟

Test Runner هو مكون في JUnit يمسح classpath، ويجد الطرق ذات التعليق التوضيحي @Test، وينشئ مثيلات فئات الاختبار ويشغل الاختبارات. في JUnit 5، يقوم بهذا الدور JUnit Platform مع محركات الاختبار المتصلة.

كيف أتحقق من أن طريقة تطرح استثناءً؟

استخدم assertThrows(Class, Executable) — يأخذ نوع الاستثناء المتوقع ولامبدا مع استدعاء الطريقة. يتحقق JUnit من أن الاستثناء قد أُلقِي فعلاً ويعيده لمزيد من الفحص.

الخلاصة

  • JUnit هو إطار الاختبارات الوحدوية القياسي لـ Java وKotlin، أساس بيئة xUnit.
  • التعليقات التوضيحية @Test و@BeforeEach و@AfterEach تدير دورة حياة فئة الاختبار.
  • التأكيدات — assertEquals وassertTrue وassertThrows تتحقق من صحة النتائج.
  • الاختبارات المعلمة باستخدام @CsvSource و@MethodSource تقلل من تكرار الكود.
  • JUnit 5 — بنية معيارية مع منصة وAPI Jupiter ودعم الإضافات.
  • التكامل مع Android — يعمل JUnit على JVM من خلال Test Runner القياسي بدون محاكي.
  • Test Runner يكتشف ويشغل طرق @Test تلقائيًا، ويبلغ عن النتائج.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا